closuresvsclosures套接字?
在C中,我明白,如果closures一个套接字,这意味着套接字将被破坏,并可以在以后重新使用。
如何关机? 说明中说,它closures了该sockets的一半双工连接。 但是,将这个套接字像close
系统调用一样被销毁?
Beej的networking指南解释了这一点。 shutdown
是阻止单向或双向通信的灵活方式。 当第二个参数是SHUT_RDWR
,它将阻止发送和接收(如close
)。 但是, close
是实际销毁套接字的方式。
随着shutdown
,你仍然可以收到对方已经发送的待处理数据(感谢Joey Adams注意到这一点)。
现有的答案没有一个告诉人们在TCP协议层面如何shutdown
和close
工作,所以值得添加。
一个标准的TCP连接通过4路完成终止:
- 一旦一个参与者没有更多的数据要发送,它发送一个FIN数据包给另一个
- 另一方为FIN返回一个ACK。
- 当另一方也完成数据传输时,它发送另一个FIN数据包
- 初始参与者返回一个ACK并完成传输。
但是,还有另一种“紧急”的方式来closuresTCP连接:
- 参与者发送RST包并放弃连接
- 对方收到一个RST,然后放弃连接
在Wireshark的testing中,使用默认的套接字选项, shutdown
将FIN数据包发送到另一端,但它只是完成了。 在对方发送FIN数据包之前,您仍然可以接收数据。 一旦发生这种情况,您的Receive
将得到一个0大小的结果。 所以,如果你是第一个closures“发送”,你应该closuressockets,一旦你完成接收数据。
另一方面,如果在连接仍然存活的情况下调用close
(另一侧仍处于活动状态,并且在系统缓冲区中也可能有未发送的数据),则RST数据包将被发送到另一侧。 这对错误很有用。 例如,如果您认为对方提供了错误的数据或拒绝提供数据(DOS攻击?),则可以立即closures套接字。
我对规则的看法是:
- 尽可能在
shutdown
之前考虑shutdown
- 如果您在决定closures之前完成接收(接收到0个大小的数据),请在上次发送(如果有)完成后closures连接。
- 如果要正常closures连接,请closures连接(使用SHUT_WR,如果您不关心在此之后接收数据,也使用SHUT_RD),然后等待,直到收到0大小的数据,然后closuressockets。
- 在任何情况下,如果发生任何其他错误(例如超时),只需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_RD
或0
进一步接收被禁止
SHUT_WR
或1
进一步发送不允许
SHUT_RDWR
或2
进一步发送和接收不允许
这可能是特定于平台,但我总是怀疑它,但无论如何,我所看到的最好的解释是在这个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_RD和SHUT_WR )将在对方发送更多数据时发送第一个数据包。