在C语言中,我明白如果我们关闭一个套接字,这意味着套接字将被销毁,以后可以重新使用。
关闭怎么样?描述说它会关闭到该套接字的双工连接的一半。但是该套接字会像close系统调用一样被销毁吗?
close
这是Beej的网络指南中的解释。shutdown是一种在一个或两个方向上阻塞通信的灵活方法。当第二个参数是SHUT_RDWR时,它将同时阻塞发送和接收(如close)。然而,close是实际销毁套接字的方法。
shutdown
SHUT_RDWR
使用shutdown,你仍然能够接收peer已经发送的未决数据(感谢Joey Adams注意到这一点)。
这可能是特定于平台的,我有点怀疑,但无论如何,我所见过的最好的解释是在这个MSDN页面,其中解释了关机,逗留选项,套接字关闭和一般连接终止序列。
总之,使用shutdown在TCP级别发送关闭序列,使用close释放进程中套接字数据结构所使用的资源。如果在调用close时还没有发出显式的关闭序列,则会为您启动一个。
如果使用shutdown(),则可以避免close()的一些限制。
shutdown()
close()
close()将终止TCP连接的两个方向。有时您希望告诉另一个端点您已经完成了发送数据,但仍然希望接收数据。
close()减少描述符引用计数(维护在文件表项中,计数当前打开的引用文件/套接字的描述符数量),如果描述符不为0,则不关闭套接字/文件。这意味着如果您正在进行fork,则只有在引用计数降为0之后才会进行清理。使用shutdown()可以启动正常的TCP关闭序列,忽略引用计数。
参数说明如下:
int shutdown(int s, int how); // s is socket descriptor
int how可以是:
int how
SHUT_RD或0 不允许进一步接收
SHUT_RD
0
SHUT_WR或1 不允许进一步发送
SHUT_WR
1
SHUT_RDWR或2 不允许进一步发送和接收
2
我也曾在linux下成功地从一个pthread中使用shutdown()迫使另一个当前阻塞在connect()中的pthread提前中止。
connect()
在其他操作系统(至少是OSX)下,我发现调用close()足以获得connect()失败。
现有的答案都没有告诉人们shutdown和close是如何在TCP协议级别上工作的,所以值得添加这个。
一个标准的TCP连接通过4种方式终止:
然而,还有另一种“紧急”的方式来关闭TCP连接:
在我用Wireshark进行的测试中,使用默认的套接字选项,shutdown将一个FIN数据包发送到另一端,但这就是它所做的一切。直到对方发送给你FIN数据包,你仍然可以收到数据。一旦发生这种情况,你的Receive将得到一个0大小的结果。因此,如果你是第一个关闭“发送”的人,你应该在完成接收数据后关闭套接字。
Receive
另一方面,如果你在连接仍然活跃的时候调用close(另一端仍然活跃,你可能在系统缓冲区中也有未发送的数据),一个RST包将被发送到另一端。这对错误很有帮助。例如,如果您认为对方提供了错误的数据或拒绝提供数据(DOS攻击?),您可以立即关闭套接字。
我对规则的看法是:
SHUT_RD和SHUT_WR的理想实现
以下内容未经测试,请自行承担风险。然而,我相信这是一种合理和实际的做事方式。
如果TCP堆栈只接收到SHUT_RD关闭,它应该将此连接标记为预期没有更多数据。任何挂起的和后续的read请求(不管它们在哪个线程中)将返回零大小的结果。但是,连接仍然是活动的和可用的——例如,您仍然可以接收OOB数据。此外,操作系统将丢弃它为这个连接接收到的任何数据。但仅此而已,没有包裹会寄到另一边。
read
如果TCP堆栈只接收到SHUT_WR关闭,它将标记此连接为不能再发送数据。所有挂起的写请求将被完成,但后续的写请求将失败。此外,一个FIN包将被发送到另一边,告诉他们我们没有更多的数据要发送。
shutdown()实际上并没有关闭文件描述符——它只是改变了它的可用性。要释放套接字描述符,需要使用close()。“1
在我的测试中。
当socket未与其他进程共享时,close将立即发送fin数据包并销毁fd
shutdown SHUT_RD,进程仍然可以从套接字接收数据,但如果TCP缓冲区为空,recv将返回0。当对等体发送更多数据后,recv将再次返回数据。
recv
shutdown SHUT_WR将发送fin包,以指示进一步的发送是不允许的。对等体可以recv数据,但如果它的TCP缓冲区是空的,它将recv 0
如果对等端发送更多数据,shutdown SHUT_RDWR(等于同时使用SHUT_RD和SHUT_WR)将发送第一个数据包。
关闭
当你用完了一个套接字,你可以简单地用close关闭它的文件描述符;如果仍有数据等待通过连接传输,通常close会尝试完成此传输。您可以使用SO_LINGER套接字选项来指定超时时间来控制这种行为;参见套接字选项。
您也可以通过调用shutdown命令仅关闭连接上的接收或传输。
shutdown命令用来关闭socket的连接。它的参数how指定执行什么动作: 0 停止接收此套接字的数据。如果进一步的数据到达,拒绝它。 1 停止尝试从这个套接字传输数据。丢弃任何等待发送的数据。停止寻找已发送数据的确认;如果它丢失了,不要重新发送。 2 停止接收和传输。< / p >
成功时返回0,失败时返回-1。
Linux: shutdown()导致侦听器线程select()唤醒并产生错误。关闭();close ();会导致无尽的等待。
Winsock:反之亦然- shutdown()没有作用,而close()被成功捕获。