Linux 中的优雅关闭服务器套接字

Posted

技术标签:

【中文标题】Linux 中的优雅关闭服务器套接字【英文标题】:Graceful Shutdown Server Socket in Linux 【发布时间】:2012-03-13 09:38:23 【问题描述】:

我希望能够停止侦听 linux 中的服务器套接字,并确保从客户端的角度打开的所有连接都得到正确处理并且不会突然关闭(即:接收 ECONNRESET)。

即:

sock = create_socket();
listen(sock, non_zero_backlog);
graceful_close(sock);

如果认为调用 close() 并处理已经接受的套接字就足够了,但是如果在服务器套接字上调用 close(),内核积压中可能会打开一些连接。

【问题讨论】:

您也许可以使用shutdown 来做到这一点。不过我还没有测试过,所以我不知道它是否会起作用。 我认为没有办法做到这一点。在此处查看讨论的结尾:fixunix.com/networking/… @drscroogemcduck 请定义“正确”的含义。根据 RFC,为半开 TCP 连接获取 RST是正确的 为什么觉得客户端接收ECONNRESET不优雅?你能提供更多关于这个问题的背景吗? listen() 告诉内核开始接受该套接字上的 tcp 连接,然后您使用 accept() 检索它们。听起来您想以某种方式“stopListening()”(即让内核停止接受传入的连接),然后调用accept() 来清空积压。此时,您可以关闭服务器套接字,而无需任何“在内核积压中打开的连接将被突然关闭”。至于你将如何停止倾听,我不知道。也许以某种方式将传入连接的内核层缓冲区大小设置为零? 【参考方案1】:

(我发现的)唯一可行的方法是:

    防止accept()添加更多客户端

    在某处有一个打开的套接字列表,并等待它们全部正确关闭,这意味着:

    使用shutdown() 告诉客户端您将不再使用该套接字

    致电read() 一段时间以确保所有客户端已发送 其间已被拉走

    然后使用close() 释放每个客户端套接字。

    那么,您可以安全地close() 监听套接字。

您可以(并且应该)使用超时来确保空闲连接不会永远持续下去。

【讨论】:

SO_REUSEADDR 似乎是本地套接字上的一个不错的解决方案,它可能仍然是最好的干净退出但可能并非在所有情况下都可能。【参考方案2】:

您正在查看 TCP 套接字 API 的限制。您可以将ECONNRESET 视为EOF 的套接字版本,或者,您可以通过TCP 实现更高级别的协议,通知客户端即将断开连接。

但是,如果您尝试后一种选择,请注意难以处理的Two Armies Problem,这使得在一般情况下无法正常关闭;这是 TCP 连接重置机制的部分动机。即使您可以以大多数时间都有效的方式编写graceful_close(),您可能仍然需要处理ECONNRESET,除非服务器进程可以永远等待从客户端接收graceful_close_ack

【讨论】:

以上是关于Linux 中的优雅关闭服务器套接字的主要内容,如果未能解决你的问题,请参考以下文章

SO_LINGER实现优雅关闭连接

Linux C 捕捉终止信号以优雅终止

为啥不尝试 I/O 就不可能检测到 TCP 套接字已被对等方优雅地关闭?

套接字:不断让 POLLHUP 处于半关闭状态

TCP/IP网络编程:07优雅地断开套接字连接

python中的广播套接字服务器[关闭]