Boost logo

Boost Users :

Subject: Re: [Boost-users] asio Socket disconnection not working in 1.38?
From: Michael Dehmlow (dehmlowm_at_[hidden])
Date: 2009-02-28 14:00:56


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--tp22230650p22265540.html
Sent from the Boost - Users mailing list archive at Nabble.com.

Boost-users list run by williamkempf at hotmail.com, kalb at libertysoft.com, bjorn.karlsson at readsoft.com, gregod at cs.rpi.edu, wekempf at cox.net