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

时间:2016-02-21 22:26:45

标签: c++ sockets

我有一个使用POCO框架编写的C ++服务器应用程序。在这种情况下,服务器应用程序充当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 个答案:

答案 0 :(得分:1)

要彻底关闭套接字:

  1. 使用override func viewWillAppear(animated: Bool) { super.viewWillAppear(animated) // Set to new colour for whole app UINavigationBar.appearance().barTintColor = UIColor.blueColor() // Or, Set to new colour for just this navigation bar self.navigationController?.navigationBar.barTintColor = UIColor.blueColor() } override func viewWillDisappear(animated: Bool) { super.viewWillDisappear(animated) //Revert to old colour, whole app UINavigationBar.appearance().barTintColor = UIColor.redColor() //Revert to old colour, just this navigation bar self.navigationController?.navigationBar.barTintColor = UIColor.redColor() } 致电shutdown
  2. 继续从套接字读取,直到读取返回零或致命错误。
  3. 关闭套接字。
  4. 请勿在关闭套接字后尝试访问套接字。
  5. 您的代码有两个主要问题。它不会确保无论发生什么情况都始终在套接字上调用SD_SEND,并且它可以在关闭套接字后访问套接字。前者导致您的CLOSE_WAIT问题。后者是一个巨大的安全漏洞。