【问题标题】:Socket is open after process, that opened it finished套接字在处理后打开,打开它完成
【发布时间】:2015-08-05 11:21:50
【问题描述】:

在服务器端关闭客户端套接字并退出应用程序后,套接字仍然打开一段时间。

我可以通过 netstat 看到它

Every 0.1s: netstat -tuplna  | grep 6676    
tcp        0      0 127.0.0.1:6676          127.0.0.1:36065         TIME_WAIT   -

我使用 log4cxx 日志记录和 telnet appender。 log4cxx 使用 apr 套接字。 Socket::close() 方法看起来像这样:

void Socket::close() {
    if (socket != 0) {
        apr_status_t status = apr_socket_close(socket);
        if (status != APR_SUCCESS) {
            throw SocketException(status);
        }        
        socket = 0;
    }
}

并且已成功处理。但是程序完成后我可以通过 netstat 看到打开的套接字,如果它再次启动 log4cxx 无法打开 6676 端口,因为它很忙。 我尝试修改 log4cxx。 关闭前关闭套接字:

void Socket::close() {
    if (socket != 0) {
        apr_status_t shutdown_status = apr_socket_shutdown(socket, APR_SHUTDOWN_READWRITE);
        printf("Socket::close shutdown_status %d\n", shutdown_status);
        if (shutdown_status != APR_SUCCESS) {
            printf("Socket::close WTF %d\n", shutdown_status != APR_SUCCESS);
            throw SocketException(shutdown_status);
        }
        apr_status_t close_status = apr_socket_close(socket);
        printf("Socket::close close_status %d\n", close_status);
        if (close_status != APR_SUCCESS) {
            printf("Socket::close WTF %d\n", close_status != APR_SUCCESS);
            throw SocketException(close_status);
        }
        socket = 0;
    }
}

但它没有帮助,错误仍然重现。

【问题讨论】:

    标签: c++ c sockets log4cxx apr


    【解决方案1】:

    这不是错误。时间等待(和关闭等待)是出于安全目的而设计的。但是,您可以调整等待时间。在任何情况下,从服务器的角度来看,套接字已关闭并且您通过 ulimit 计数器放松,除非您进行压力测试,否则它不会产生太大的可见影响。

    【讨论】:

      【解决方案2】:

      正如 Calvin 所说,这不是错误,而是一项功能。 Time Wait 是一个套接字状态,表示该套接字不再使用,但还不能被重用。

      假设您打开了一个套接字,并且某个客户端正在发送数据。当服务器关闭其套接字时,数据可能会在网络中备份或在传输中。

      现在假设您再次启动服务或启动一些新服务。线路上的数据包不知道它是一项新服务,并且该服务无法知道数据包的目的地是已消失的服务。新服务可能会尝试解析数据包并失败,因为它们采用某种奇怪的格式,或者客户端可能会收到不相关的错误并继续尝试发送,可能是因为序列号不匹配并且接收主机会收到一些奇怪的错误。通过定时等待,客户端将收到有关套接字已关闭的通知,并且服务器不会潜在地获得奇怪的数据。双赢。它等待的时间应该足够从系统中清除所有传输中的数据。

      查看这篇文章了解更多信息:Socket options SO_REUSEADDR and SO_REUSEPORT, how do they differ? Do they mean the same across all major operating systems?

      【讨论】:

        【解决方案3】:

        TIME_WAIT 是一个套接字状态,允许所有可能从连接中保留的旅行数据包在连接参数(源地址、源端口、目标地址、目标端口)之前到达或死亡可以再次重复使用。内核只需设置一个计时器,等待这段时间过去,然后再允许您再次重用该套接字。但是你不能缩短它(即使你可以,你最好不要这样做),因为你不可能知道是否还有数据包正在传输或加速或杀死它们。您唯一的可能是等待绑定到该端口的套接字超时并从状态TIME_WAIT 传递到CLOSED 状态。

        如果您被允许重用连接(我认为有一个选项或可以在 linux 内核中完成某些操作)并且您收到一个旧的连接数据包,您可以由于收到的数据包而重置连接。这可能会导致新连接出现更多问题。解决了这些问题,您需要等待属于旧连接的所有流量都死掉或到达目的地,然后再再次使用该套接字。

        【讨论】:

          猜你喜欢
          • 2013-10-25
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2013-09-11
          • 2018-07-12
          • 1970-01-01
          • 2017-09-28
          • 1970-01-01
          相关资源
          最近更新 更多