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

关闭怎么样?描述说它会关闭到该套接字的双工连接的一半。但是这个套接字会像关闭系统调用一样被销毁吗?


当前回答

现有的答案都没有告诉人们在TCP协议级别上关闭和关闭是如何工作的,因此值得添加这个。

一个标准的TCP连接通过4种方式终止:

当一个参与者没有更多的数据要发送时,它会向另一个参与者发送FIN数据包 另一方对FIN返回ACK。 当另一方也完成数据传输后,发送另一个FIN报文 初始参与者返回一个ACK并完成传输。

然而,还有另一种“紧急”的方式来关闭TCP连接:

日志含义与会者发送RST报文并放弃连接 另一方接收到RST,然后也放弃连接

在我用Wireshark进行的测试中,使用默认的套接字选项,shutdown将一个FIN数据包发送到另一端,但这就是它所做的一切。直到对方发送给你FIN数据包,你仍然可以收到数据。一旦发生这种情况,Receive将得到一个0大小的结果。因此,如果你是第一个关闭“发送”的人,你应该在完成接收数据后关闭套接字。

另一方面,如果你在连接仍然活跃的时候调用close(另一方仍然活跃,你可能在系统缓冲区中也有未发送的数据),一个RST包将被发送到另一方。这对错误很有帮助。例如,如果您认为对方提供了错误的数据或拒绝提供数据(DOS攻击?),您可以立即关闭套接字。

我对规则的看法是:

Consider shutdown before close when possible If you finished receiving (0 size data received) before you decided to shutdown, close the connection after the last send (if any) finished. If you want to close the connection normally, shutdown the connection (with SHUT_WR, and if you don't care about receiving data after this point, with SHUT_RD as well), and wait until you receive a 0 size data, and then close the socket. In any case, if any other error occurred (timeout for example), simply close the socket.

SHUT_RD和SHUT_WR的理想实现

以下内容未经测试,请自行承担风险。然而,我相信这是一种合理和实际的做事方式。

如果TCP堆栈只接收到SHUT_RD关闭,它应该将此连接标记为预期没有更多数据。任何挂起的和后续的读请求(不管它们在哪个线程中)将返回零大小的结果。但是,连接仍然是活动的和可用的——例如,您仍然可以接收OOB数据。此外,操作系统将丢弃它为这个连接接收到的任何数据。但仅此而已,没有包裹会寄到另一边。

如果TCP堆栈只接收到SHUT_WR关闭,它将标记此连接为不能再发送数据。所有挂起的写请求将被完成,但后续的写请求将失败。此外,一个FIN包将被发送到另一边,告诉他们我们没有更多的数据要发送。

其他回答

这在Beej的网络指南中有解释。关闭是一种在一个或两个方向上阻止通信的灵活方式。当第二个参数是SHUT_RDWR时,它将同时阻塞发送和接收(如close)。然而,close实际上是销毁套接字的方法。

在关闭状态下,您仍然能够接收到对等端已经发送的待处理数据(感谢Joey Adams注意到这一点)。

关闭

当你用完了一个套接字,你可以简单地用close关闭它的文件描述符;如果仍有数据等待通过连接传输,通常close会尝试完成此传输。您可以使用SO_LINGER套接字选项来指定超时时间来控制这种行为;参见套接字选项。

关闭

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

shutdown函数用来关闭套接字的连接。它的参数how指定执行什么动作: 0 停止接收此套接字的数据。如果进一步的数据到达,拒绝它。 1 停止尝试从这个套接字传输数据。丢弃任何等待发送的数据。停止寻找已发送数据的确认;如果它丢失了,不要重新发送。 2 停止接收和传输。

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

现有的答案都没有告诉人们在TCP协议级别上关闭和关闭是如何工作的,因此值得添加这个。

一个标准的TCP连接通过4种方式终止:

当一个参与者没有更多的数据要发送时,它会向另一个参与者发送FIN数据包 另一方对FIN返回ACK。 当另一方也完成数据传输后,发送另一个FIN报文 初始参与者返回一个ACK并完成传输。

然而,还有另一种“紧急”的方式来关闭TCP连接:

日志含义与会者发送RST报文并放弃连接 另一方接收到RST,然后也放弃连接

在我用Wireshark进行的测试中,使用默认的套接字选项,shutdown将一个FIN数据包发送到另一端,但这就是它所做的一切。直到对方发送给你FIN数据包,你仍然可以收到数据。一旦发生这种情况,Receive将得到一个0大小的结果。因此,如果你是第一个关闭“发送”的人,你应该在完成接收数据后关闭套接字。

另一方面,如果你在连接仍然活跃的时候调用close(另一方仍然活跃,你可能在系统缓冲区中也有未发送的数据),一个RST包将被发送到另一方。这对错误很有帮助。例如,如果您认为对方提供了错误的数据或拒绝提供数据(DOS攻击?),您可以立即关闭套接字。

我对规则的看法是:

Consider shutdown before close when possible If you finished receiving (0 size data received) before you decided to shutdown, close the connection after the last send (if any) finished. If you want to close the connection normally, shutdown the connection (with SHUT_WR, and if you don't care about receiving data after this point, with SHUT_RD as well), and wait until you receive a 0 size data, and then close the socket. In any case, if any other error occurred (timeout for example), simply close the socket.

SHUT_RD和SHUT_WR的理想实现

以下内容未经测试,请自行承担风险。然而,我相信这是一种合理和实际的做事方式。

如果TCP堆栈只接收到SHUT_RD关闭,它应该将此连接标记为预期没有更多数据。任何挂起的和后续的读请求(不管它们在哪个线程中)将返回零大小的结果。但是,连接仍然是活动的和可用的——例如,您仍然可以接收OOB数据。此外,操作系统将丢弃它为这个连接接收到的任何数据。但仅此而已,没有包裹会寄到另一边。

如果TCP堆栈只接收到SHUT_WR关闭,它将标记此连接为不能再发送数据。所有挂起的写请求将被完成,但后续的写请求将失败。此外,一个FIN包将被发送到另一边,告诉他们我们没有更多的数据要发送。

Linux: shutdown()导致侦听器线程select()唤醒并产生错误。关闭();close ();会导致无尽的等待。

Winsock:反之亦然- shutdown()没有作用,而close()被成功捕获。

这可能是特定于平台的,我有点怀疑,但无论如何,我所见过的最好的解释是在这个msdn页面上,他们解释了关机,逗留选项,套接字关闭和一般连接终止序列。

总之,使用shutdown在TCP级别发送关闭序列,使用close释放进程中套接字数据结构所使用的资源。如果在调用close时还没有发出显式的关闭序列,则会为您启动一个。