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

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


当前回答

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

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

其他回答

关闭

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

关闭

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

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

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

我还成功地在linux下使用shutdown()从一个pthread强制另一个pthread当前阻塞在connect()提前中止。

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

如果改用shutdown(),则可以避免close()的一些限制。

close()将终止TCP连接的两个方向。有时您希望告诉另一个端点您已经完成了发送数据,但仍然希望接收数据。

Close()减少描述符引用计数(维护在文件表项中,计数当前打开的引用文件/套接字的描述符数量),如果描述符不为0,则不关闭套接字/文件。这意味着如果您正在进行fork,则只有在引用计数降为0之后才会进行清理。使用shutdown()可以启动正常的TCP关闭序列,忽略引用计数。

参数说明如下:

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

Int如何:

SHUT_RD或0 不允许进一步接收

SHUT_WR或1 不允许进一步发送

SHUT_RDWR或2 不允许进一步发送和接收

shutdown()实际上并没有关闭文件描述符——它只是改变了它的可用性。要释放套接字描述符,需要使用close()。“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包将被发送到另一边,告诉他们我们没有更多的数据要发送。