ChatGPT解决这个技术问题 Extra ChatGPT

socket.shutdown 与 socket.close

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

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

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


A
Arvid

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

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

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

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

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


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

这是一个explanation

一旦不再需要套接字,调用程序可以通过对套接字描述符应用关闭子例程来丢弃套接字。如果在发生关闭时可靠的传递套接字具有与之关联的数据,则系统会继续尝试数据传输。但是,如果数据仍未交付,系统将丢弃该数据。如果应用程序对任何未决数据没有用处,它可以在关闭套接字之前使用套接字上的关闭子例程。


D
Dale Reidy

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

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

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

IMO 名称“关闭”和“关闭”具有误导性,“关闭”和“销毁”会强调它们的区别。


它并不向另一端表明没有进一步阅读的意图。关闭读取不会向对等方发送任何内容。
m
mykhal

它在 Socket Programming HOWTO (py2/py3) 中有提及

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


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

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

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

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


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

有几种关闭方式:http://msdn.microsoft.com/en-us/library/system.net.sockets.socket.shutdown.aspx。 *nix 类似。


关机有一种“味道”,它有两种选择,可以组合使用。这里没有任何东西可以回答实际的问题。
u
user306166

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

这在

1- 缓冲区刷新

2-奇怪的错误检测

3- 安全防护

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

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

但是,这是不可撤销的,因此您可以在完全发送所有数据之后执行此操作,并且您希望确保它至少在对等操作系统缓冲区中


关机不会强制冲洗。缓冲情况不变。如果缓冲区不为空,则不会引发错误。 FIN 仅仅排在待处理数据的后面。答案是完全错误的。