简体   繁体   中英

boost::asio tcp server disconnect issue

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 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));
}

The problem was in putty. I was using it for testing the server using telnet and duplicating the sessions as needed. There seems to be a bug in putty that causes the socket not to get closed when you close the windows for a session. The sockets are all closed only when the last session of putty is closed.

Thank you all for the help provided

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM