Answers:
Beej的网络指南对此进行了说明。 shutdown
是一种在一个或两个方向上阻止通信的灵活方式。当第二个参数为时SHUT_RDWR
,它将同时阻止发送和接收(如close
)。然而,close
是实际销毁套接字的方法。
使用shutdown
,您仍然可以接收对等方已经发送的未决数据(感谢Joey Adams注意到了这一点)。
shutdown
两个方向的一个原因close
是,如果您使用FILE
引用了套接字fdopen
。如果close
使用套接字,则可以为新打开的文件分配相同的fd,随后使用FILE
会读取/写入错误的位置,这可能是非常糟糕的。如果您只是shutdown
,则随后使用FILE
会给出错误,直到fclose
被调用为止。
shutdown
:来向对等体发送EOF信号,并且仍然能够接收对等体发送的未决数据。
现有的答案都没有告诉人们如何shutdown
以及close
在TCP协议级别工作,因此值得添加这一点。
标准的TCP连接通过4向终结来终止:
但是,还有另一种“紧急”方式来关闭TCP连接:
在我对Wireshark的测试中,使用默认的套接字选项,shutdown
将FIN数据包发送到另一端,但这就是它的全部工作。在另一方向您发送FIN数据包之前,您仍然可以接收数据。一旦发生这种情况,您的Receive
将为0。因此,如果您是第一个关闭“发送”的人,则在完成接收数据后应关闭套接字。
另一方面,如果您致电 close
在连接仍处于活动状态时(另一端仍处于活动状态,并且系统缓冲区中也可能有未发送的数据),则RST数据包将发送到另一端。这对错误有好处。例如,如果您认为另一方提供了错误的数据或拒绝提供数据(DOS攻击?),则可以立即关闭套接字。
我对规则的看法是:
shutdown
先考虑close
SHUT_RD和SHUT_WR的理想实现
以下未经过测试,请您自担风险。但是,我相信这是一种合理实用的处理方式。
如果TCP堆栈仅使用SHUT_RD接收到关闭消息,则应将此连接标记为没有更多数据。任何未决的和后续的read
请求(无论它们处于哪个线程)都将以零大小的结果返回。但是,该连接仍处于活动状态并且可用-例如,您仍然可以接收OOB数据。而且,操作系统将删除为此连接收到的所有数据。但这就是所有包都不会发送到另一端。
如果TCP堆栈仅通过SHUT_WR接收到关闭,它将标记该连接,因为无法再发送任何数据。所有挂起的写请求将完成,但随后的写请求将失败。此外,FIN数据包将发送到另一端,以通知他们我们没有更多数据要发送。
shutdown()
连接,然后它不再存在。您仍然具有文件描述符。您仍然可以recv()
从接收缓冲区。而且您仍然需要调用close()
以处置文件描述符。
close()
如果使用shutdown()
某项限制,可以避免一些限制。
close()
将终止TCP连接上的两个方向。有时您想告诉另一个端点您已经完成了发送数据,但是仍然想要接收数据。
close()
减少描述符引用计数(保留在文件表条目中,并计数当前打开的引用文件/套接字的描述符的数目),并且如果描述符不为0,则不关闭套接字/文件。这意味着,如果要分叉,只有在参考计数降至0后才进行清除。使用shutdown()
1可以启动普通TCP关闭序列而忽略参考计数。
参数如下:
int shutdown(int s, int how); // s is socket descriptor
int how
可:
SHUT_RD
或0
禁止进一步接收
SHUT_WR
或1
禁止进一步发送
SHUT_RDWR
或2
禁止进一步发送和接收
“ shutdown()实际上并不关闭文件描述符,它只是改变其可用性。要释放套接字描述符,您需要使用close()。” 1个
关
使用完套接字后,只需使用close关闭它的文件描述符即可。如果仍有数据等待通过连接传输,则通常关闭尝试完成此传输。您可以使用SO_LINGER套接字选项来指定超时时间,以控制此行为。请参阅套接字选项。
关掉
您也可以通过调用shutdown来仅关闭连接上的接收或传输。
关闭功能将关闭套接字的连接。它的参数如何指定要执行的操作:0停止接收此套接字的数据。如果进一步的数据到达,则拒绝它。1停止尝试从此套接字传输数据。丢弃所有等待发送的数据。停止寻找已发送数据的确认;如果丢失,请勿重新传输。2停止接收和发送。
成功时返回值为0,失败时返回-1。
在我的测试中。
close
当套接字未与其他进程共享时,将发送fin数据包并立即销毁fd
shutdown
SHUT_RD,进程仍然可以从套接字接收数据,但是recv
如果TCP缓冲区为空,则返回0,对等体发送更多数据recv
后将再次返回数据。
shutdown
SHUT_WR将发送fin数据包以指示不允许进一步发送。对等方可以接收数据,但是如果其TCP缓冲区为空,它将接收0
shutdown
如果对等方发送更多数据,则SHUT_RDWR(等于使用SHUT_RD和SHUT_WR)将发送第一个数据包。
close()
在Linux而不是FIN上发送了RST。
recv()
将再次返回数据”是不正确的。2.对等方之后发送更多数据的行为SHUT_RD
取决于平台。