socket.shutdown 与 socket.close

Posted

技术标签:

【中文标题】socket.shutdown 与 socket.close【英文标题】:socket.shutdown vs socket.close 【发布时间】:2010-09-29 09:58:21 【问题描述】:

我最近看到了一些看起来像这样的代码(当然 sock 是一个套接字对象):

sock.shutdown(socket.SHUT_RDWR)
sock.close()

在套接字上调用shutdown然后关闭它的目的到底是什么?如果有所不同,则此套接字正在用于非阻塞 IO。

【问题讨论】:

【参考方案1】:

这是explanation:

一旦不再需要套接字, 调用程序可以丢弃 通过应用关闭子例程进行套接字 到套接字描述符。如果一个 可靠的传递套接字有数据 关闭时与之相关联 地方,系统继续尝试 数据传输。但是,如果数据是 仍未送达,系统丢弃 数据。应否申请 程序对任何未决的程序都没有用处 数据,它可以使用关机 套接字上的子程序之前 关闭它。

【讨论】:

【参考方案2】:

关机和关闭说明:Graceful shutdown (msdn)

关闭(在您的情况下)向连接的另一端表明没有进一步读取或写入套接字的意图。然后关闭释放与套接字关联的所有内存。

省略关闭可能会导致套接字在操作系统堆栈中逗留,直到连接被正常关闭。

IMO 名称“shutdown”和“close”具有误导性,“close”和“destroy”会强调它们的区别。

【讨论】:

并不向对方表明没有进一步阅读的意图。关闭读取不会向对等方发送任何内容。【参考方案3】:

有一些关闭的味道:http://msdn.microsoft.com/en-us/library/system.net.sockets.socket.shutdown.aspx。 *nix 类似。

【讨论】:

关机有一种“味道”,有两种选择,可以组合使用。这里没有回答实际问题。【参考方案4】:

调用closeshutdown 对底层套接字有两种不同的影响。

首先要指出的是,套接字是底层操作系统中的资源,多个进程可以拥有同一个底层套接字的句柄。

当您调用close 时,它会将句柄计数减一,如果句柄计数达到零,则套接字和关联的连接将通过正常关闭过程(有效地向对等方发送 FIN / EOF)和套接字已解除分配。

这里要注意的是,如果句柄计数没有达到零,因为另一个进程仍然有套接字的句柄,那么连接不会关闭,套接字也不会被释放。

另一方面,调用shutdown 进行读写会关闭底层连接并向对等方发送一个FIN / EOF,而不管有多少进程拥有套接字句柄。但是,它不会释放套接字,之后您仍然需要调用 close。

【讨论】:

很好的答案,我从不费心去了解shutdown() 做了什么:) 读操作的shutdown() 会导致它发送一个FIN 数据包吗?即关机(sock_fd, 1); 总是拨打.shutdown() 并在下一行拨打.close() 是否明智?或者之间应该有延迟? @Luc 完全取决于你在做什么。 @Luc 只要没有其他进程拥有套接字句柄,只要关闭就可以了。【参考方案5】:

Shutdown(1) ,强制套接字不发送更多数据

这在

中很有用

1- 缓冲区刷新

2- 奇怪的错误检测

3- 安全防护

让我再解释一下,当您将数据从 A 发送到 B 时,不能保证是 发送到 B ,只保证发送到 A os 缓冲区, 然后将其发送到 B os 缓冲区

因此,通过在 A 上调用 shutdown(1),您会刷新 A 的缓冲区并引发错误 如果缓冲区不为空,即:数据尚未发送到对等方

但是这是不可逆转的,所以你可以在你完全之后再做 发送了您的所有数据,并且您希望确保它至少在对等方 操作系统缓冲区

【讨论】:

关机不会强制刷新。缓冲情况不变。如果缓冲区不为空,则不会引发错误。 FIN 仅仅排在待处理数据的后面。答案完全错误。【参考方案6】:

上面这段代码是不是错了?

在shutdown 调用之后直接调用close 可能会使内核丢弃所有传出缓冲区。

根据 http://blog.netherlabs.nl/articles/2009/01/18/the-ultimate-so_linger-page-or-why-is-my-tcp-not-reliable 需要在关机和关闭之间等待,直到读取返回 0。

【讨论】:

不正确。如果连接已重置,内核只会丢弃传出缓冲区,如果本地应用程序尚未读取所有已到达的待处理入站数据,或者如果对等点与 SO_LINGER 混淆,则可能会发生这种情况,他们不应该这样做.也没有必要睡觉,甚至在关闭之前也不需要调用shutdown。关于这件事有很多错误信息。【参考方案7】:

在 Socket Programming HOWTO (py2/py3) 中提到过

断开连接

严格来说,您应该在close 之前在套接字上使用shutdownshutdown 是对另一端套接字的建议。根据您传递的参数,它可能意味着“我不再发送,但我仍然会听”,或“我不听,再见! ”。 然而,大多数套接字库都习惯于程序员忽略使用这条礼仪,通常closeshutdown(); close() 相同。 所以在大多数情况下,不需要显式关闭。

...

【讨论】:

此信息不正确。只有在以下情况下才需要关闭套接字以进行写入:(1)您已经分叉了该进程并且确实希望现在发送 FIN,或者(2)您正在进行相互读取 - EOS 协议,使得两个对等方同时关闭。否则close() 就足够了。应该更正 Python 文档。

以上是关于socket.shutdown 与 socket.close的主要内容,如果未能解决你的问题,请参考以下文章

C语言 socket shutdown()函数(将与 sockfd 关联的套接字上的全双工连接全部或部分关闭)

如何关闭在while循环中的线程中侦听的阻塞套接字?

socket编程模式理解与对比

socket原理与粘包

Socket与系统调用深度分析

Socket常用语法与socketserver实例