I am currently writing a TCP server using boost::asio TCP socket. I've used the examples provided to make the server be statefull by wrapping the socket object in my own session object.
Everything works fine except for the disconnect. In my setup I always have a async_read_some call for each opened socket.
Normal behavior is when I connect a client and disconnect it. The data read handler is called with the error being set so I know that I have a socket disconnected.
The bad behavior is when I connect 2 clients in one order and close them in the same order.
When I close the first client I get no handler being called but when I close the second one I get also the call for the first client, both to notify the disconnect.
Except for this issue everything seems to be working nicely. Send and receive of data on multiple clients is working fine.
Anyone had this issue ? What could be the cause for this ?
bool TCPNetworkListener::StartListener()
{
//check if already started
if (m_SocketAcceptor.is_open())
{
return false;
}
//create the socket acceptor
m_SocketAcceptor.open(m_TCPEndpoint.protocol());
m_SocketAcceptor.set_option(boost::asio::ip::tcp::acceptor::reuse_address(true));
m_SocketAcceptor.bind(m_TCPEndpoint);
m_SocketAcceptor.listen();
//accept async connections
m_lastConnectedClientId++;
TCPNetworkSession::SharedPtr new_session(new TCPNetworkSession(m_IOService, this, m_lastConnectedClientId));
m_SocketAcceptor.async_accept(new_session->GetSocket(),
boost::bind(&TCPNetworkListener::HandleNewConnection, this, new_session,
boost::asio::placeholders::error));
//all fine
m_listenerState = NetworkListener::NLState_Running;
return true;
}
void TCPNetworkListener::HandleNewConnection( TCPNetworkSession::SharedPtr session, const boost::system::error_code& error )
{
if (error)
{
return;
}
session->StartNewSession();
//accept new async connections
m_lastConnectedClientId++;
TCPNetworkSession::SharedPtr new_session(new TCPNetworkSession(m_IOService, this, m_lastConnectedClientId));
m_SocketAcceptor.async_accept(new_session->GetSocket(),
boost::bind(&TCPNetworkListener::HandleNewConnection, this, new_session,
boost::asio::placeholders::error));
}
The session looks like this:
TCPNetworkSession::TCPNetworkSession( boost::asio::io_service& io_service , TCPNetworkListener* handler, long clientId) :
m_socket(io_service),
m_IOService(io_service),
m_networkHandler(handler),
m_clientId(clientId),
m_sendingData(false)
{
}
tcp::socket& TCPNetworkSession::GetSocket()
{
return m_socket;
}
void TCPNetworkSession::StartNewSession()
{
//notify of new connection established
if (m_networkHandler)
{
m_networkHandler->ClientConnected(shared_from_this());
}
m_socket.set_option(boost::asio::socket_base::keep_alive(true));
//try to read the first message data
m_socket.async_read_some(
boost::asio::buffer(m_readBuffer, SOCKETBUFFERLENGTH),
boost::bind(&TCPNetworkSession::HandleReadData, shared_from_this(), boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred));
}
void TCPNetworkSession::HandleReadData( const boost::system::error_code& error, std::size_t bytes_transferred )
{
if (error)
{
//we have got disconnected
if (m_networkHandler)
{
m_networkHandler->ClientDisconnected(shared_from_this());
}
return;
}
//we received new data
if (m_networkHandler)
{
m_readBuffer[bytes_transferred] = 0;
std::string strData(reinterpret_cast<const char*>(m_readBuffer), bytes_transferred);
m_networkHandler->ClientDataReceived(shared_from_this(), strData);
}
//try to read the next message data
m_socket.async_read_some(
boost::asio::buffer(m_readBuffer, SOCKETBUFFERLENGTH),
boost::bind(&TCPNetworkSession::HandleReadData, shared_from_this(), boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred));
}
io_service::run
, and when this blocking gets released you receive the both handlers? (BTW, 1.41 is a bit outdated) – Igor R.