closuresvsclosures套接字?

在C中,我明白,如果closures一个套接字,这意味着套接字将被破坏,并可以在以后重新使用。

如何关机? 说明中说,它closures了该sockets的一半双工连接。 但是,将这个套接字像close系统调用一样被销毁?

Beej的networking指南解释了这一点。 shutdown是阻止单向或双向通信的灵活方式。 当第二个参数是SHUT_RDWR ,它将阻止发送和接收(如close )。 但是, close是实际销毁套接字的方式。

随着shutdown ,你仍然可以收到对方已经发送的待处理数据(感谢Joey Adams注意到这一点)。

现有的答案没有一个告诉人们在TCP协议层面如何shutdownclose工作,所以值得添加。

一个标准的TCP连接通过4路完成终止:

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

但是,还有另一种“紧急”的方式来closuresTCP连接:

  1. 参与者发送RST包并放弃连接
  2. 对方收到一个RST,然后放弃连接

在Wireshark的testing中,使用默认的套接字选项, shutdown将FIN数据包发送到另一端,但它只是完成了。 在对方发送FIN数据包之前,您仍然可以接收数据。 一旦发生这种情况,您的Receive将得到一个0大小的结果。 所以,如果你是第一个closures“发送”,你应该closuressockets,一旦你完成接收数据。

另一方面,如果在连接仍然存活的情况下调用close (另一侧仍处于活动状态,并且在系统缓冲区中也可能有未发送的数据),则RST数据包将被发送到另一侧。 这对错误很有用。 例如,如果您认为对方提供了错误的数据或拒绝提供数据(DOS攻击?),则可以立即closures套接字。

我对规则的看法是:

  1. 尽可能在shutdown之前考虑shutdown
  2. 如果您在决定closures之前完成接收(接收到0个大小的数据),请在上次发送(如果有)完成后closures连接。
  3. 如果要正常closures连接,请closures连接(使用SHUT_WR,如果您不关心在此之后接收数据,也使用SHUT_RD),然后等待,直到收到0大小的数据,然后closuressockets。
  4. 在任何情况下,如果发生任何其他错误(例如超时),只需closures套接字。

SHUT_RD和SHUT_WR的理想实现

以下未经testing,请自负风险。 不过,我相信这是一个合理而实际的做事方式。

如果TCP堆栈只接收到SHUT_RD的closures,则应将此连接标记为不再需要数据。 任何挂起和随后的read请求(无论它们在哪个线程中)将返回零大小的结果。 但是,连接仍处于活动状态并且可用 – 例如,仍可以接收OOB数据。 此外,操作系统将丢弃它为此连接收到的任何数据。 但是,就是这样,没有包裹会被送到另一边。

如果TCP栈只收到SHUT_WR的closures,则应该标记该连接为不能再发送数据。 所有挂起的写入请求都将完成,但后续写入请求将失败。 此外,一个FIN数据包将被发送到另一端通知他们我们没有更多的数据要发送。

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

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

close()递减描述符的引用计数(保存在文件表项中并计算当前打开的引用文件/套接字的描述符的数量),并且如果描述符不为0,则不closures套接字/文件。这意味着如果你只有在引用计数下降到0之后,清除才会发生。使用shutdown()可以启动正常的TCPclosures序列,忽略引用计数。

参数如下:

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

int how可以:

SHUT_RD0进一步接收被禁止

SHUT_WR1进一步发送不允许

SHUT_RDWR2进一步发送和接收不允许

这可能是特定于平台,但我总是怀疑它,但无论如何,我所看到的最好的解释是在这个msdn页面上 ,他们解释closures,延迟选项,套接字closures和一般连接终止序列。

总之,请使用shutdown在TCP级别发送closures序列,并使用close来释放进程中套接字数据结构使用的资源。 如果您在通话结束之前还没有发出明确的关机顺序,则会为您启动一个关机程序。

我也在Linux下使用shutdown()从一个pthread中强制成功,以强制当前在connect()阻塞的另一个pthread以尽早中止。

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

“shutdown()实际上并不closures文件描述符,它只是改变了它的可用性。为了释放一个套接字描述符,你需要使用close()。 1

当你完成一个套接字的使用时,你可以简单地closures其文件描述符; 如果仍然有数据等待通过连接传输,则常闭尝试完成此传输。 您可以使用SO_LINGER套接字选项来控制此行为来指定超时期限; 请参阅Socket选项。

关掉

您也可以通过调用关机来closures连接上的接收或传输。

closuresfunctionclosures了套接字的连接。 它的参数如何指定要执行的操作:0停止接收此套接字的数据。 如果进一步的数据到达,拒绝它。 1停止尝试从此套接字传输数据。 丢弃等待发送的数据。 停止寻找已经发送的数据的确认; 如果丢失,不要转发。 2停止接收和传输。

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

在我的testing。

close会发送fin包,并在套接字不与其他进程共享时立即销毁fd

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

shutdown SHUT_WR将发送fin数据包以指示进一步的发送不被允许。 对端可以收到数据,但是如果它的TCP缓冲区是空的,它将收到0

shutdown SHUT_RDWR (等于同时使用SHUT_RDSHUT_WR )将在对方发送更多数据时发送第一个数据包。