关闭与关机套接字?


214

在C语言中,我了解到,如果我们关闭一个套接字,则意味着该套接字将被销毁,以后可以重新使用。

如何关机?描述说关闭了与该套接字的双工连接的一半。但是那个套接字会像close系统调用一样被销毁吗?


以后不能重复使用。已经关门了 完了 做完了
洛恩侯爵

Answers:


191

Beej的网络指南对此进行了说明shutdown是一种在一个或两个方向上阻止通信的灵活方式。当第二个参数为时SHUT_RDWR,它将同时阻止发送和接收(如close)。然而,close是实际销毁套接字的方法。

使用shutdown,您仍然可以接收对等方已经发送的未决数据(感谢Joey Adams注意到了这一点)。


23
请记住,即使您关闭()TCP套接字,它也不一定立即可重用,因为它将处于TIME_WAIT状态,同时操作系统会确保没有未完成的数据包,如果您将这些数据包混淆为新信息,立即将那个套接字重用于其他用途。
alesplin

91
套接字的关闭与关闭之间的最大区别是套接字与其他进程共享时的行为。shutdown()影响套接字的所有副本,而close()仅影响一个进程中的文件描述符。
Zan Lynx 2010年

5
您可能要同时使用shutdown两个方向的一个原因close是,如果您使用FILE引用了套接字fdopen。如果close使用套接字,则可以为新打开的文件分配相同的fd,随后使用FILE会读取/写入错误的位置,这可能是非常糟糕的。如果您只是shutdown,则随后使用FILE会给出错误,直到fclose被调用为止。
R .. GitHub停止帮助ICE,2010年

25
关于TIME_WAIT的评论不正确。这适用于端口,不适用于套接字。您不能重用套接字。
洛恩侯爵,2010年

48
-1。这篇文章和链接都省略了一个重要的概念性原因,要使用shutdown:来向对等体发送EOF信号,并且仍然能够接收对等体发送的未决数据。
乔伊·亚当斯

144

现有的答案都没有告诉人们如何shutdown以及close在TCP协议级别工作,因此值得添加这一点。

标准的TCP连接通过4向终结来终止:

  1. 一旦参与者没有更多数据要发送,它将向其他参与者发送FIN数据包
  2. 另一方返回FIN的ACK。
  3. 当另一方也完成数据传输时,它将发送另一个FIN数据包
  4. 初始参与者返回ACK并完成传输。

但是,还有另一种“紧急”方式来关闭TCP连接:

  1. 参与者发送RST数据包并放弃连接
  2. 另一端收到RST,然后也放弃连接

在我对Wireshark的测试中,使用默认的套接字选项,shutdown将FIN数据包发送到另一端,但这就是它的全部工作。在另一方向您发送FIN数据包之前,您仍然可以接收数据。一旦发生这种情况,您的Receive将为0。因此,如果您是第一个关闭“发送”的人,则在完成接收数据后应关闭套接字。

另一方面,如果您致电 close在连接仍处于活动状态时(另一端仍处于活动状态,并且系统缓冲区中也可能有未发送的数据),则RST数据包将发送到另一端。这对错误有好处。例如,如果您认为另一方提供了错误的数据或拒绝提供数据(DOS攻击?),则可以立即关闭套接字。

我对规则的看法是:

  1. 尽可能shutdown先考虑close
  2. 如果在决定关闭之前完成接收(接收到0个大小的数据),请在最后一次发送(如果有)完成后关闭连接。
  3. 如果您想正常关闭连接,请关闭连接(使用SHUT_WR,并且如果以后不希望接收数据,也可以使用SHUT_RD),然后等待直到收到大小为0的数据,然后关闭连接插座。
  4. 无论如何,如果发生任何其他错误(例如超时),只需关闭套接字即可。

SHUT_RD和SHUT_WR的理想实现

以下未经过测试,请您自担风险。但是,我相信这是一种合理实用的处理方式。

如果TCP堆栈仅使用SHUT_RD接收到关闭消息,则应将此连接标记为没有更多数据。任何未决的和后续的read请求(无论它们处于哪个线程)都将以零大小的结果返回。但是,该连接仍处于活动状态并且可用-例如,您仍然可以接收OOB数据。而且,操作系统将删除为此连接收到的所有数据。但这就是所有包都不会发送到另一端。

如果TCP堆栈仅通过SHUT_WR接收到关闭,它将标记该连接,因为无法再发送任何数据。所有挂起的写请求将完成,但随后的写请求将失败。此外,FIN数据包将发送到另一端,以通知他们我们没有更多数据要发送。


2
“如果您在连接仍处于活动状态时调用关闭”是重言式的,并且不会导致发送RST。(1)是不必要的。在(4)中,超时不一定对连接致命,也不总是表示可以关闭它。
2014年

4
@EJP不,它不是重言式的。您可以shutdown()连接,然后它不再存在。您仍然具有文件描述符。您仍然可以recv()从接收缓冲区。而且您仍然需要调用close()以处置文件描述符。
PavelŠimerda'16

这是有关电汇格式的最佳答案。我会对使用SHUT_RD关闭的更多详细信息感兴趣。没有不希望有更多数据的TCP信号,对吗?难道不只有FIN可以发送更多数据吗?
PavelŠimerda'16

3
@PavelŠimerda是TCP不会发信号通知不要期望更多数据。这应该在高级协议中考虑。我认为,这通常不是必需的。您可以关闭门,但不能阻止人们在门前放礼物。这是他们的决定,而不是您的决定。
地球引擎

1
@EJP您有任何实际论点吗?否则我不感兴趣。
帕维尔·希默达(PavelŠimerda)'11

35

close()如果使用shutdown()某项限制,可以避免一些限制。

close()将终止TCP连接上的两个方向。有时您想告诉另一个端点您已经完成了发送数据,但是仍然想要接收数据。

close()减少描述符引用计数(保留在文件表条目中,并计数当前打开的引用文件/套接字的描述符的数目),并且如果描述符不为0,则不关闭套接字/文件。这意味着,如果要分叉,只有在参考计数降至0后才进行清除。使用shutdown()1可以启动普通TCP关闭序列而忽略参考计数。

参数如下:

int shutdown(int s, int how); // s is socket descriptor

int how 可:

SHUT_RD0 禁止进一步接收

SHUT_WR1 禁止进一步发送

SHUT_RDWR2 禁止进一步发送和接收


8
这两个功能的目的完全不同。如果尚未启动套接字,则套接字上的最后关闭将启动关闭序列,这一事实并不能改变关闭是用于清理套接字数据结构而关闭是用于启动tcp级别关闭序列的事实。
Len Holgate

25
您不能“改用关机”。您也可以使用它但是您必须关闭插座一段时间。
罗恩侯爵

15

这可能是特定于平台的,我对此有些怀疑,但是无论如何,我所见过的最好的解释是在此msdn页面上,它们解释了关机,延迟选项,套接字关闭和常规连接终止顺序。

总之,使用shutdown在TCP级别发送关闭序列,并使用close释放进程中套接字数据结构使用的资源。如果在您调用close时尚未发出明确的关机顺序,则会为您启动一个关机顺序。


9

在Linux下,我还使用shutdown()一个pthread强制当前阻塞的另一个pthread connect()提前中止,从而获得了成功。

在其他操作系统(至少是OSX)下,我发现调用close()足以connect()失败。


7

“ shutdown()实际上并不关闭文件描述符,它只是改变其可用性。要释放套接字描述符,您需要使用close()。” 1个


3

使用完套接字后,只需使用close关闭它的文件描述符即可。如果仍有数据等待通过连接传输,则通常关闭尝试完成此传输。您可以使用SO_LINGER套接字选项来指定超时时间,以控制此行为。请参阅套接字选项。

关掉

您也可以通过调用shutdown来仅关闭连接上的接收或传输。

关闭功能将关闭套接字的连接。它的参数如何指定要执行的操作:0停止接收此套接字的数据。如果进一步的数据到达,则拒绝它。1停止尝试从此套接字传输数据。丢弃所有等待发送的数据。停止寻找已发送数据的确认;如果丢失,请勿重新传输。2停止接收和发送。

成功时返回值为0,失败时返回-1。


2

在我的测试中。

close 当套接字未与其他进程共享时,将发送fin数据包并立即销毁fd

shutdown SHUT_RD,进程仍然可以从套接字接收数据,但是recv如果TCP缓冲区为空,则返回0,对等体发送更多数据recv后将再次返回数据。

shutdown SHUT_WR将发送fin数据包以指示不允许进一步发送。对等方可以接收数据,但是如果其TCP缓冲区为空,它将接收0

shutdown 如果对等方发送更多数据,则SHUT_RDWR(等于使用SHUT_RDSHUT_WR)将发送第一个数据包。


我只是尝试了一下,然后close()在Linux而不是FIN上发送了RST。
PavelŠimerda'16

您还真的要声明在关闭读取端后,程序将接收更多数据吗?
PavelŠimerda'16

@PavelŠimerda我认为发送RST或FIN可能取决于tcp状态?我不确定。
simpx

1.“对等方发送更多数据后,recv()将再次返回数据”是不正确的。2.对等方之后发送更多数据的行为SHUT_RD取决于平台。
罗恩侯爵

@EJP我尝试过自己,很抱歉,我忘记了我在哪个平台上进行此测试(centos或Mac)。这就是我得到的
simpx
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.