关闭vs关闭套接字?

时间:2010-11-11 23:38:22

标签: c sockets networking

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

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

9 个答案:

答案 0 :(得分:172)

这是Beej网络指南中的explainedshutdown是阻止一个或两个方向通信的灵活方式。当第二个参数为SHUT_RDWR时,它将阻止发送和接收(如close)。但是,close是实际销毁套接字的方法。

使用shutdown,您仍然可以接收对等方已发送的待处理数据(感谢Joey Adams注意到这一点)。

答案 1 :(得分:115)

现有的答案都没有告诉人们shutdownclose在TCP协议级别的工作原理,因此值得添加。

标准TCP连接通过4路终结终止:

  1. 一旦参与者没有更多数据要发送,它就会向另一个
  2. 发送FIN数据包
  3. 另一方为FIN返回ACK。
  4. 当另一方也完成数据传输时,它会发送另一个FIN数据包
  5. 初始参与者返回ACK并完成转移。
  6. 然而,还有另一种“紧急”方式来关闭TCP连接:

    1. 参与者发送RST数据包并放弃连接
    2. 另一方收到RST,然后放弃连接
    3. 在我使用Wireshark进行的测试中,使用默认套接字选项,shutdown将FIN数据包发送到另一端,但确实如此。在另一方向您发送FIN数据包之前,您仍然可以接收数据。一旦发生这种情况,您的Receive将获得0大小的结果。因此,如果您是第一个关闭“发送”的人,则应在收到数据后关闭套接字。

      另一方面,如果在连接仍处于活动状态时调用close(另一端仍然处于活动状态,并且系统缓冲区中可能还有未发送的数据),则会发送一个RST数据包另一边。这有利于错误。例如,如果您认为对方提供了错误的数据或拒绝提供数据(DOS攻击?),您可以立即关闭套接字。

      我对规则的看法是:

      1. 在可能的shutdown之前考虑close
      2. 如果在决定关闭之前完成了接收(接收的0大小数据),请在最后一次发送(如果有)完成后关闭连接。
      3. 如果要正常关闭连接,请关闭连接(使用SHUT_WR,如果您在此之后不关心接收数据,也使用SHUT_RD),并等待直到收到0大小的数据,并且然后关闭插座。
      4. 在任何情况下,如果发生任何其他错误(例如超时),只需关闭套接字。
      5. SHUT_RD和SHUT_WR的理想实现

        以下未经过测试,相信风险自负。但是,我认为这是一种合理而实用的做事方式。

        如果TCP堆栈仅通过SHUT_RD接收关闭,则应将此连接标记为不再需要数据。任何挂起和后续read请求(无论它们处于哪个线程)都将返回零大小的结果。但是,连接仍然是活动的和可用的 - 例如,您仍然可以接收OOB数据。此外,操作系统将删除它为此连接接收的任何数据。但就是这样,没有包裹会被送到另一方。

        如果TCP堆栈仅通过SHUT_WR收到关闭,它应标记此连接,因为不能再发送数据。所有挂起的写入请求都将完成,但后续写入请求将失败。此外,FIN数据包将被发送到另一方通知他们我们没有更多数据要发送。

答案 2 :(得分:35)

close()存在一些限制,如果使用shutdown(),则可以避免这种限制。

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

close()递减描述符引用计数(在文件表条目中维护并计算当前打开的指向文件/套接字的描述符的数量),并且如果描述符不为0则不关闭套接字/文件。这意味着如果您正在分叉,则仅在引用计数降至0后才进行清理。使用shutdown()可以启动正常的TCP关闭序列,忽略引用计数。

参数如下:

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

int how可以是:

SHUT_RD0     不允许进一步接收

SHUT_WR1     不允许进一步发送

SHUT_RDWR2     不允许进一步发送和接收

答案 3 :(得分:15)

这可能是特定于平台的,我有点怀疑它,但无论如何,我见过的最好的解释是here on this msdn page,他们解释了关闭,延迟选项,套接字闭包和一般连接终止序列。

总之,使用shutdown在TCP级别发送关闭序列,并使用close来释放进程中套接字数据结构使用的资源。如果您在调用close时尚未发出明确的关闭序列,则会启动一个关闭序列。

答案 4 :(得分:7)

我在linux下使用shutdown()从一个pthread中取得成功,迫使另一个当前在connect()中被阻止的pthread提前中止。

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

答案 5 :(得分:7)

" shutdown()实际上没有关闭文件描述符 - 它只是改变了它的可用性。要释放套接字描述符,您需要使用close()。" 1

答案 6 :(得分:3)

关闭

完成套接字使用后,只需关闭即可关闭文件描述符;如果仍有数据等待通过连接传输,通常关闭会尝试完成此传输。您可以使用SO_LINGER套接字选项控制此行为以指定超时期限;请参阅套接字选项。

<强>关闭

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

关闭功能会关闭套接字的连接。它的参数如何指定要执行的操作: 0 停止接收此套接字的数据。如果有更多数据到达,请拒绝。 1 停止尝试从此套接字传输数据。丢弃等待发送的任何数据。停止寻找已发送数据的确认;如果丢失则不要重新发送。 2 停止接收和传输。

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

答案 7 :(得分:1)

在我的测试中。

close将在未与其他进程共享套接字时立即发送fin数据包并销毁fd

shutdown SHUT_RD ,进程仍然可以从套接字中恢复数据,但如果TCP缓冲区为空,则recv将返回0。对等体发送更多数据后,{{1将再次返回数据。

recv SHUT_WR 将发送fin数据包以指示不允许进一步发送。对等体可以收集数据,但如果TCP缓冲区为空,它将收回0

shutdown SHUT_RDWR (等于同时使用 SHUT_RD SHUT_WR )如果对等方发送更多数据,则会发送第一个数据包。< / p>

答案 8 :(得分:1)

linux:shutdown()导致侦听器线程select()唤醒并产生错误。关掉();关();将导致无尽的等待。

winsock:反之亦然-当成功捕获close()时,shutdown()无效。