Question

I am trying to implement a simple HTTP server. I am able to send the HTTP response to clients but the issue is that on Firefox I get "Connection Reset" error. IE too fails, while Chrome works perfectly and displays the HTML I sent in the response.

If I telnet to my server then I get "Connection Lost" message, just after the response. So, from this I concluded that connection is not getting closed properly. Below are important snippets from the code.

class TCPServer - This initiates the acceptor (boost::asio::ip::tcp::acceptor) object.

void TCPServer::startAccept()
{
    TCPConnection::pointer clientConnection =
        TCPConnection::create(acceptor.io_service());

    acceptor.async_accept(clientConnection->getSocket(),
        boost::bind(&TCPServer::handleAccept, this, clientConnection,
    boost::asio::placeholders::error));
}

void TCPServer::handleAccept(TCPConnection::pointer clientConnection,
    const boost::system::error_code& error)
   {
    std::cout << "Connected with a remote client." << std::endl;
if (!error)
{   
    clientConnection->start();
    startAccept();
}
   }

class TCPConnection - Represents a TCP connection to client. This extends - public boost::enable_shared_from_this<TCPConnection>

TCPConnection::TCPConnection(boost::asio::io_service& ioService)
: socket(ioService)
{
}
TCPConnection::~TCPConnection(void)
{
    std::cout << "TCPConnection destructor called." << std::endl;
}

TCPConnection::pointer TCPConnection::create(boost::asio::io_service& ioService)
{
    return pointer(new TCPConnection(ioService));
}

tcp::socket& TCPConnection::getSocket()
{
    return socket;
}

void TCPConnection::start()
{
//ASSUME outBuf has some data.. It is initialized elsewhere.
    boost::asio::async_write(socket, boost::asio::buffer(*outBuf),
    boost::bind(&TCPConnection::handleWrite, shared_from_this(),
    boost::asio::placeholders::error,
    boost::asio::placeholders::bytes_transferred));
    std::cout << "Transferring " << outBuf->size() << " bytes." << std::endl;
}

void TCPConnection::handleWrite(const boost::system::error_code& err, size_t bytesTransferred)
{
    std::cout << "Sent " << bytesTransferred << " bytes. Error:: " << err << std::endl;
    socket.shutdown(boost::asio::ip::tcp::socket::shutdown_both);
    socket.close();
    std::cout << "TCP connection closed." << std::endl;
}

One important point that I should mention is that since objects of TCPConnection are pointed to by 'smart pointers' so when execution of TCPConnection::handleWrite finishes then there are no pointers left to point at this TCPConnection object. So immediately after handleWrite finishes, the TCPConnection's destructor is called.

Was it helpful?

Solution

The server should not close the socket. If the server closes the socket and the client sends more data or there is data in the receive queue then the client will receive a RST causing this error. See http://cs.baylor.edu/~donahoo/practical/CSockets/TCPRST.pdf

The HTTP server should read the entire client request or in the case of HTTP/1.1 the entire sequence of client requests. In this example it does not read any of the client request so there is data in the receive queue, so that the client receives a reset.

Drain the socket with a sequences of async_reads before closing - probably in the future you will want to actually parse the client request ;-)

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top