
Thanks Igor for the suggestion but the async_read_some takes a handle to a function and that would require some serious rethinking of my code. I used to use a socket select on a single socket to see if there was any data for my socket. Since ::select marks a socket as ready for has some data or there is an error on the socket. Any time select returned true I was able to read the socket without worry that the socket would block. I really think that availble() should populate an error if the client has been disconnected and there are zero bytes to be read, this would in affect give the user some of the best parts of select without the backwardness of select. I was able to solve my problem with the following: boost::system::error_code ec; boost::asio::socket_base::non_blocking_io command(true); socket.io_control(command); bytesRead = _socket->read_some(boost::asio::buffer(data, dataBufferSize), ec); if(error&&boost::asio::error::would_block!=error) { //there is some other error the client has disconnected; } else { //I must have got some data or theres no data yet check bytesRead for that } It is important to give an error_code object to the call otherwise it will throw even if you catch the exception it will really kill your performance (not to mention make debugging a nightmare). A couple of things to note. Using an acceptor seems flakey when you set non blocking to true(You may want to unset it before you call acept on the socket again). If you set io_control without a peer the call will throw so you cant just create the socket then make the io_control call you must wait for the peer to connect. IMHO it would be great if the was an overloaded read_some call that takes a flag not to block. I hope I saved some on the 16 hours I spent on this ;) Don't get be wrong another awesome library from boost. I would have become and accountant long ago with out you. Thank fellas. peace, Mike D. Michael Dehmlow wrote:
I'm trying to detect that a peer has been disconnected using the asio socket library. Below is a source listing of a unit test that I have created (which is one of several that I have tried; ask for more listings if nesasary) to figure out a reliable method to do so.
I've also tried using (and have unit test listings for) the availble(errorCode) call the sock1.remote_endpoint(errorCode); calls.
I need a way to detect that a client has been disconnected from my server without blocking.
I've even tried using the read_some call with the io_control non_blocking option set but the then read some returns an error every time read_some is called.
[code] for(int i=0;i<1;i++) { boost::asio::io_service ioServ1; boost::asio::io_service ioServ2; boost::asio::io_service ioServ3; boost::asio::io_service ioServ4;
boost::asio::ip::tcp::socket sock1(ioServ1);
boost::asio::ip::tcp::socket sock3(ioServ3);
SocketAcceptor sA1(ioServ1,sock1,std::string("localHost"),8321); SocketAcceptor sA2(ioServ3,sock3,std::string("localHost"),8322);
// The socket acceptor class simple starts a thread and and accept(_mySocket,ec) // with a boost::asio::ip::tcp::acceptor. If thread does not completed in the time passed in //the milliseconds then the call then the the accept call will return. sA1.accept(10); sA2.accept(10);
boost::asio::ip::tcp::socket sock2(ioServ2); boost::asio::ip::tcp::socket sock4(ioServ4);
boost::asio::ip::tcp::resolver resolver1(ioServ2); boost::asio::ip::tcp::resolver::query query1(boost::asio::ip::tcp::v4(), "localhost", (boost::lexical_cast<std::string>(8321)).c_str()); boost::asio::ip::tcp::resolver::iterator iterator1 = resolver1.resolve(query1);
boost::asio::ip::tcp::resolver resolver2(ioServ4); boost::asio::ip::tcp::resolver::query query2(boost::asio::ip::tcp::v4(), "localhost", (boost::lexical_cast<std::string>(8322)).c_str()); boost::asio::ip::tcp::resolver::iterator iterator2 = resolver2.resolve(query2);
sock2.connect(*iterator1); sock4.connect(*iterator2);
TS_ASSERT_EQUALS(sA1.accept(200),true); TS_ASSERT_EQUALS(sA2.accept(200),true); boost::system::error_code errorCode;
//std::cout<<"about to read some from socket"<<std::endl; //boost::asio::socket_base::non_blocking_io command(true); //sock1.io_control(command);
//TS_ASSERT_EQUALS(sock1.read_some(boost::asio::buffer(data, length), errorCode),0); //std::cout<<"Hopefully that didn't take long"<<std::endl;
sock2.close(); sock4.close();
//just a boost wrapped sleep call Thread::sleep(2000);
//this assertion will always fail just used to see what is in the errorCode object. TS_ASSERT_EQUALS(boost::asio::error::eof,errorCode);
sock1.available(errorCode); TS_ASSERT(errorCode); TS_ASSERT_EQUALS(boost::asio::error::eof,errorCode);
sock2.available(errorCode); TS_ASSERT(errorCode); TS_ASSERT_EQUALS(boost::asio::error::eof,errorCode);
//TS_ASSERT_EQUALS(sock3.read_some(boost::asio::buffer(data, length), errorCode),0); //TS_ASSERT_EQUALS(boost::asio::error::eof,errorCode); // TS_ASSERT(errorCode);
sock3.available(errorCode); TS_ASSERT(errorCode); TS_ASSERT_EQUALS(boost::asio::error::eof,errorCode);
sock3.available(errorCode); TS_ASSERT(errorCode); TS_ASSERT_EQUALS(boost::asio::error::eof,errorCode);
//TS_ASSERT_EQUALS(sock2.read_some(boost::asio::buffer(data, length), errorCode),0); //TS_ASSERT_EQUALS(boost::asio::error::eof,errorCode); //TS_ASSERT(errorCode);
sock4.available(errorCode); TS_ASSERT(errorCode); TS_ASSERT_EQUALS(boost::asio::error::eof,errorCode);
//TS_ASSERT_EQUALS(sock4.read_some(boost::asio::buffer(data, length), errorCode),0); //TS_ASSERT_EQUALS(boost::asio::error::eof,errorCode);
//TS_ASSERT(errorCode);
TS_ASSERT(!sock1.is_open()); TS_ASSERT(!sock3.is_open()); } [/code] The output:
//expected failure Error: Expected (boost::asio::error::eof == errorCode), found ({ 02 00 00 00 } != { 00 00 00 00 38 A4 63 00 })
//sock1 no errorCode Error: Assertion failed: errorCode //sock1 no errorCode Error: Expected (boost::asio::error::eof == errorCode), found ({ 02 00 00 00 } != { 00 00 00 00 38 A4 63 00 })
//-------------------------------- //sock2 ALWAYS returns an errorcode //-------------------------------- //sock2 some other errorCode
Error: Expected (boost::asio::error::eof == errorCode), found ({ 02 00 00 00 } != { 19 27 00 00 38 A4 63 00 })
//sock3 no errorCode Error: Assertion failed: errorCode
Error: Expected (boost::asio::error::eof == errorCode), found ({ 02 00 00 00 } != { 00 00 00 00 38 A4 63 00 }) //sock4 no errorCode Error: Assertion failed: errorCode Error: Expected (boost::asio::error::eof == errorCode), found ({ 02 00 00 00 } != { 00 00 00 00 38 A4 63 00 })
//-------------------------------- //sock4 ALWAYS returns an errorcode //-------------------------------- //sock4 some other errorCode
Error: Expected (boost::asio::error::eof == errorCode), found ({ 02 00 00 00 } != { 19 27 00 00 38 A4 63 00 }) //is_open doesn't seem all that helpful either Error: Assertion failed: !sock1.is_open() Error: Assertion failed: !sock3.is_open()
-- View this message in context: http://www.nabble.com/asio-Socket-disconnection-not-working-in-1.38--tp22230... Sent from the Boost - Users mailing list archive at Nabble.com.