boost::asio 无法完全关闭 TCP 连接

发布于 2024-09-08 16:45:46 字数 2419 浏览 9 评论 0原文

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

如果我远程登录到我的服务器,那么我会在响应之后收到“连接丢失”消息。因此,由此我得出结论,连接没有正确关闭。以下是代码中的重要片段。

class 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

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 的析构函数。

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.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

挽你眉间 2024-09-15 16:45:46

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

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

在关闭之前使用一系列 async_reads 排空套接字 - 也许将来您会想要实际解析客户端请求;-)

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

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文