首页 文章

处于CLOSE_WAIT状态时,套接字send()挂起

提问于
浏览
0

我有一个C服务器应用程序,使用POCO框架编写 . 在这种情况下,服务器应用程序充当HTTP服务器 . 有一个客户端应用程序,我无法控制,无法调试,导致服务器出现问题 . 客户端请求一个大文件,该文件作为HTTP响应返回 . 在文件返回期间,客户端关闭连接 . 我看到套接字移动到CLOSE_WAIT状态,表明客户端已发送FIN . 问题是在我的应用程序中,send()函数然后挂起导致我的一个HTTP线程基本上丢失,并且一旦所有线程进入此状态,服务器就没有响应 .

发送代码在POCO框架内,但看起来像这样:

do
    {
            if (_sockfd == POCO_INVALID_SOCKET) throw InvalidSocketException();
            rc = ::send(_sockfd, reinterpret_cast<const char*>(buffer), length, flags);
    }
    while (_blocking && rc < 0 && lastError() == POCO_EINTR);
    if (rc < 0) error();
    return rc;

(调用此函数时标志为0) . 我尝试通过添加以下代码来检测此状态:

char c;
    int r;
    int rc;
    do
    {
            // Check if FIN received                                                                                                                                                                                                                                                                                                                                    
            while ((r = recv(_sockfd, &c, 1, MSG_DONTWAIT)) == 1) {}
            if (r == 0) { ::close(_sockfd); _sockfd = POCO_INVALID_SOCKET; } // FIN received                                                                                                                                                                                                                                                                            
            if (_sockfd == POCO_INVALID_SOCKET) throw InvalidSocketException();

            rc = ::send(_sockfd, reinterpret_cast<const char*>(buffer), length, flags);
    }
    while (_blocking && rc < 0 && lastError() == POCO_EINTR);
    if (rc < 0) error();
    return rc;

这似乎可以使事情变得更好,但仍然无法解决问题 . 我最终得到的服务器没有快速挂起,但更多CLOSE_WAIT套接字,所以我认为我已经部分解决了线程挂起问题,但我仍然没有正确地从破坏的套接字中整理好 . 随着这种变化,问题发生得越来越少,但仍然会发生,所以我认为关键是要理解为什么send()会挂起 .

我在linux上测试这段代码 .

1 回答

  • 1

    要干净地关闭套接字:

    • 使用 SD_SEND 调用 shutdown .

    • 继续从套接字读取,直到读取返回零或致命错误 .

    • 关闭套接字 .

    • 关闭套接字后,请勿尝试访问套接字 .

    您的代码有两个主要问题 . 无论发生什么情况,它都不能确保始终在套接字上调用 close ,它可以在关闭套接字后访问套接字 . 前者导致您的CLOSE_WAIT问题 . 后者是一个巨大的安全漏洞 .

相关问题