boost::asio 无法干净地关闭 TCP 连接

Posted

技术标签:

【中文标题】boost::asio 无法干净地关闭 TCP 连接【英文标题】:boost::asio fails to close TCP connection cleanly 【发布时间】:2010-07-03 04:26:16 【问题描述】:

我正在尝试实现一个简单的 HTTP 服务器。我能够向客户端发送 HTTP 响应,但问题是在 Firefox 上我收到“连接重置”错误。 IE 也失败了,而 Chrome 可以完美运行并显示我在响应中发送的 html

如果我 telnet 到我的服务器,那么我会在响应之后收到“连接丢失”消息。因此,由此我得出结论,连接没有正确关闭。下面是代码中重要的sn-ps。

类 TCPServer - 这会启动接受器 (boost::asio::ip::tcp::acceptor) 对象。

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 - 表示到客户端的 TCP 连接。这扩展了 - public boost::enable_shared_from_this&lt;TCPConnection&gt;

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;

我应该提到的重要一点是,由于 TCPConnection 的对象是由“智能指针”指向的,所以当 TCPConnection::handleWrite 的执行完成时,就没有指向这个 TCPConnection 对象的指针了。因此,在handleWrite 完成后立即调用TCPConnection 的析构函数。

【问题讨论】:

当您的 TCPConnection 对象超出范围时,您希望在写入处理程序中发生什么?您描述的行为似乎与您的代码一致,发送响应后套接字已关闭。 【参考方案1】:

服务器不应关闭套接字。如果服务器关闭套接字并且客户端发送更多数据或接收队列中有数据,则客户端将收到导致此错误的 RST。见http://cs.baylor.edu/~donahoo/practical/CSockets/TCPRST.pdf

HTTP 服务器应该读取整个客户端请求,或者在 HTTP/1.1 的情况下读取整个客户端请求序列。在这个例子中,它没有读取任何客户端请求,所以接收队列中有数据,因此客户端接收到一个重置。

在关闭之前用 async_reads 序列排空套接字 - 可能在将来你会想要真正解析客户端请求 ;-)

【讨论】:

以上是关于boost::asio 无法干净地关闭 TCP 连接的主要内容,如果未能解决你的问题,请参考以下文章

boost::asio 完全断开连接

boost::asio::ip::tcp::iostream,首先启动客户端并等待服务器?

boost :: asio :: ip :: tcp :: iostream,首先启动客户端并等待服务器?

安全地完成读取操作 (Boost.Asio)

当服务器关闭时,客户端上的 boost asio 写操作被阻止

基于 Boost.ASIO 的 HTTP 客户端库(如 libcurl)[关闭]