套接字打开后进程,表示打开完毕

Socket is open after process, that opened it finished

本文关键字:表示 进程 套接字      更新时间:2023-10-16

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

我可以通过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。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 %dn", shutdown_status);
        if (shutdown_status != APR_SUCCESS) {
            printf("Socket::close WTF %dn", shutdown_status != APR_SUCCESS);
            throw SocketException(shutdown_status);
        }
        apr_status_t close_status = apr_socket_close(socket);
        printf("Socket::close close_status %dn", close_status);
        if (close_status != APR_SUCCESS) {
            printf("Socket::close WTF %dn", close_status != APR_SUCCESS);
            throw SocketException(close_status);
        }
        socket = 0;
    }
}

但是没有帮助,bug仍然复制。

这不是一个bug。时间等待(和关闭等待)是为了安全目的而设计的。不过,您可以调整等待时间。在任何情况下,从服务器的角度来看,套接字是关闭的,并且您被ulimit计数器放松,除非您正在进行压力测试,否则它没有太多可见的影响。

正如Calvin所指出的,这不是一个bug,这是一个特性。Time Wait是一种套接字状态,表示这个套接字不再被使用,但仍然不能被重用。

假设你有一个打开的套接字,一些客户端正在发送数据。当服务器关闭其套接字时,数据可能在网络中备份或正在运行。

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

看看这篇文章的一些额外的信息:套接字选项SO_REUSEADDR和SO_REUSEPORT,他们有什么不同?它们在所有主流操作系统中都是相同的吗?

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

如果你被允许重用连接(我认为有一个选项或一些东西可以在linux内核中完成),你收到一个旧的连接数据包,你可以得到一个连接重置,由于收到的数据包。这可能会在新的连接中导致更多的问题。在您再次使用该套接字之前,请等待属于旧连接的所有流量死亡或到达目的地。