Re: [Boost-users] boost asio async_read_some
Igor, Thanks for the response. I've been out for a few days, so I haven't been able to reply. Here is a self-contained example that illustrates the problem. This example creates a echo server thread that should echo back to the caller anything the caller sends to the thread. (Note that I have a windows Sleep() in there.) The server thread appears to do what I expect. The client thread works until the call to async_read_some(). The call returns, but I never hit the breakpoint I set in my handler, nor do I see any output from the handler. Igor, or anyone, please have a look... Thanks, Chris =============================================START================================================== #include <string> #include <boost/asio.hpp> #include <boost/bind.hpp> #include <boost/smart_ptr.hpp> #include <boost/thread.hpp> const static unsigned int cMaxLength = 512; static const std::string cStopEchoCommand("STOP_ECHO"); static boost::asio::io_service ioService; //needs to have the same life span as socket, or longer static boost::asio::ip::tcp::resolver lResolver(ioService); //------------------------------------------------------------------------------------------------- static int doConnect(std::string& ipAddress, std::string& portNumber, boost::shared_ptr<boost::asio::ip::tcp::socket>& inOutSocket) { using boost::asio::ip::tcp; try { tcp::resolver::query query(tcp::v4(), ipAddress.c_str(), portNumber.c_str()); tcp::resolver::iterator endpoint_iterator = lResolver.resolve(query); tcp::resolver::iterator end; if (inOutSocket == NULL) { boost::shared_ptr<tcp::socket> tmpSocketPtr(new tcp::socket(ioService)); inOutSocket = tmpSocketPtr; } boost::system::error_code error = boost::asio::error::host_not_found; while (error && endpoint_iterator != end) { inOutSocket->close(); inOutSocket->connect(*endpoint_iterator++, error); } if (error) { return -1; } } catch(...) { return -1; } return 0; } //Server routine static void session(unsigned int port) { using boost::asio::ip::tcp; boost::asio::io_service io_service; tcp::acceptor a(io_service, tcp::endpoint(tcp::v4(), port)); tcp::socket sock(io_service); try { bool done = false; a.accept(sock); for (;;) { char data[cMaxLength]; boost::system::error_code error; size_t length = sock.read_some(boost::asio::buffer(data, cMaxLength), error); if (error == boost::asio::error::eof) { // done, stop echoing, wait for another connection break; } else if (error) { std::cerr << "Error while receiving: " << boost::system::system_error(error).what() << "\n"; // TODO report failure break; // closing. } else if (length == cStopEchoCommand.length()) { //See if it's time to end if (cStopEchoCommand.compare(0, cStopEchoCommand.length(), data)) { break; } } else { //boost::asio::write(sock, boost::asio::buffer(data, length)); int bytesWritten = sock.write_some(boost::asio::buffer(data, length)); if (bytesWritten == 0) { std::cerr << "Error while writing to socket: " << boost::system::system_error(error).what() << "\n"; } } } } catch (std::exception& e) { // TODO report failure std::cerr << "Exception in thread: " << e.what() << "\n"; } } class TestClass { public: TestClass(std::string ipAddress, std::string port):mIPAddress(ipAddress), mPort(port) {} void PollReadhandler(const boost::system::error_code& error, size_t bytes_transferred) { mDataReadFromPoll = true; boost::system::error_code e; std::cout << "DELETE ME; PollReadhandler called()" << "\n"; } void testTCPIP() { using boost::asio::ip::tcp; // Start an separate thread which echoes all trafic to the port. std::istringstream i(mPort); unsigned int port; i >> port; mDataReadFromPoll = false; boost::thread echoTcpServer(boost::bind(session, port)); boost::shared_ptr<tcp::socket> socketPtr; int ret = doConnect(mIPAddress, mPort, socketPtr); if (ret) { std::cerr << "Failed to get connection" << std::endl; return; } //------------------------------------------------------------------------------------------------- // test sync. read char buffer[512]; unsigned int bytesRead; std::string test1Str("Test 1"); std::size_t len = socketPtr->write_some(boost::asio::buffer(test1Str.c_str(), test1Str.length())); Sleep(1000); //Windows try { int readError = 0; std::vector<unsigned char> readVectorBuffer(32); //unsigned char readVectorBuffer[512]; boost::system::error_code e; //unsigned int amtRead = socketPtr->read_some(boost::asio::buffer(readVectorBuffer, 512), e); unsigned int amtRead = socketPtr->read_some(boost::asio::buffer(readVectorBuffer, 32), e); if (amtRead != test1Str.length()) { std::cerr << "read_some read an unexpected number of bytes" << std::endl; return; } std::string s(readVectorBuffer.begin(),readVectorBuffer.end()); std::cout << "read_some returned:" << s << std::endl; } catch (...) { std::cerr << "Problem with read_some" << std::endl; } //------------------------------------------------------------------------------------------------- // test async. read std::string test2Str("Test 2"); len = socketPtr->write_some(boost::asio::buffer(test2Str.c_str(), test2Str.length())); Sleep(1000); //Poll while (!mDataReadFromPoll) { socketPtr->async_read_some(boost::asio::buffer(buffer, 512), boost::bind(&TestClass::PollReadhandler, this, boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred)); Sleep(1000); } //NEVER REACHES HERE mDataReadFromPoll = false; len = socketPtr->write_some(boost::asio::buffer(cStopEchoCommand.c_str(), cStopEchoCommand.length())); // Wait until the server thread is finished. echoTcpServer.join(); } //------------------------------------------------------------------------------------------------- private: std::string mIPAddress; std::string mPort; bool mDataReadFromPoll; }; int main() { TestClass testCase("127.0.0.1", "2222"); testCase.testTCPIP(); } =============================================END==================================================== ---------- Forwarded message ---------- From: "Igor R" <boost.li...@gmail.com> Date: Dec 4, 1:44 am Subject: boost asio async_read_some To: BOOST Archives _______________________________________________ Boost-users mailing list Boost-us...@lists.boost.orghttp://lists.boost.org/mailman/listinfo.cgi/boost-users
Here's a simplified version of my call and handler:
unsigned char tmpBuffer[512]; //global
void MyClass::handler(const boost::system::error_code& error, size_t bytes_transferred) { boost::system::error_code e; std::cerr << "handler called()" << "\n"; }
void MyClass::test() {
... socketPtr->async_read_some(boost::asio::buffer(tmpBuffer, 512), boost::bind(&MyClass::handler, this, boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred)); }
Can anyone give me any idea as to how I can get my handler to be called?
Could you please provide some code-excerpt that should compile and work? I.e. code that contains socket initialization, io_service run and your object creation - because the mistake is probably somewhere at those points.
Invocation of the handler will be performed in a manner equivalent to using boost::asio::io_service::post()." I'm not sure exactly what this means...what is this equivalent manner that is mentioned?
It means that the handler would be invoked in one of the threads that run the io_service object used by the socked.- Hide quoted text - - Show quoted text -
The client thread works until the call to async_read_some(). The call returns, but I never hit the breakpoint I set in my handler, nor do I see any output from the handler.
I can't see where you call io_service::run(). If your socket's io_service is not running, noone would process your async. calls. Please, refer to the asio examples/tutorial to find out how to organize an asyncronous i/o.
Thanks for the pointer Igor. I overlooked this part of some of the examples. Ultimately, what I want is a client that does sync. reads and writes, but also polls for data using async. reads., all using the same socket. Looking at some of the examples, it looks like polling would be done by starting another async_read from the handler supplied to the async_read. Thanks again, Chris =======================
Looking at some of the examples, it looks like polling would be done by starting another async_read from the handler supplied to the async_read.
Yes, exactly. In general, you can mix sync/async i/o, but note that you should not start a read operation before the previous read (on the same socket) is completed (the same about write).
Hmm...it's still not working for me. To the code I posted before, I added the call ioService.run(); in the doConnect() routine, after the loop where the connect is done. I get the same behavior: after the async_read_some() is called, I can see the the buffer is updated (so it read what was there), but my handler was never called. I'm sure there's a simpler explanation for my problem, but, FWIW, looking at the stack for the async_read_some call, I see the call to WSARecv(). I don't have much experience with that routine, but I did notice that the last argument(LPWSAOVERLAPPED_COMPLETION_ROUTINE) was hardcoded to 0. This may be correct, but at first glance it seems like that should be a handler to my handler routine. -- =======================
participants (2)
-
Chris Freehill
-
Igor R