为什么我应该在关闭套接字之前使用shutdown()?

时间:2017-01-25 15:48:25

标签: c++ sockets

在此MSDN页面上:

Sending and Receiving Data on the Client

建议使用以下方法关闭套接字的发送方:

shutdown(SOCK_ID, SD_SEND);

我为什么要这样?

也许我没有,它只是一个推荐?也许是为了节省记忆?也许是为了速度?

有没有人有想法?

3 个答案:

答案 0 :(得分:3)

答案在shutdown()文档中:

  

如果how参数为SD_SEND,则不允许后续调用send函数。 对于TCP套接字,在接收方发送并确认所有数据后,将发送FIN

     

...

     

要确保所有数据在关闭之前在已连接的套接字上发送和接收,应用程序应在调用shutdown 之前使用closesocket关闭连接。等待远程端已发送其所有数据并启动正常断开连接的通知的一种方法使用WSAEventSelect函数,如下所示:

     
      
  1. 致电WSAEventSelect注册FD_CLOSE通知。
  2.   
  3. 使用shutdown 致电how=SD_SEND
  4.   
  5. 收到FD_CLOSE时,请调用recvWSARecv,直到该功能成功完成并指示已收到零字节。如果返回SOCKET_ERROR,则无法进行正常断开连接。
  6.   
  7. 致电closesocket
  8.         

    等待远程端已发送所有数据并启动正常断开连接的通知的另一种方法是使用重叠的接收呼叫:

         
        
    1. 使用shutdown 致电how=SD_SEND
    2.   
    3. 调用recvWSARecv,直到函数成功完成,并指示接收到零字节。如果返回SOCKET_ERROR,则无法进行正常断开连接。
    4.   
    5. 致电closesocket
    6.         

      ...

           

      有关详情,请参阅Graceful Shutdown, Linger Options, and Socket Closure

      部分

换句话说,至少对于TCP,调用shutdown(SD_SEND)会通知对等方您已完成发送更多数据,并且很可能很快就会关闭您的连接。同样,同伴也会为你做同样的礼貌。这样,两个对等体都可以知道连接在两端都是有意关闭的。这称为正常断开连接,而不是中止异常断开连接。

默认情况下,如果您不调用shutdown(SD_SEND)closesocket()将尝试为您执行正常关机 UNLESS 已禁用套接字linger选项。最好不要依赖这种行为,除非你有充分的理由不这样做,否则你应该在致电shutdown()之前自己致电closesocket()

答案 1 :(得分:2)

除以下情况外,这是不必要和多余的:

  1. 您希望实现同步关闭,如Remy Lebeau引用的文档中所述。
  2. 套接字以某种方式被复制,例如它与子进程或父进程共享,或通过API共享,并且您希望确保现在发送FIN。
  3. 您的应用程序协议要求对等方收到关机但需要继续发送。例如,在编写代理服务器时可能会出现这种情况。
  4. 您的套接字接收缓冲区中可能有未读数据,并且您希望关闭并忽略它并在激发连接重置之前发送FIN,如果有未读的待处理数据,则会在关闭时发生。
  5. 这是我在大约30年内遇到过的唯一案例:可能还有其他案例,但我并不知道。

答案 2 :(得分:1)

没有与在套接字上发送或接收操作相关联的特定资源,套接字可以使用也可以关闭。关闭的原因与资源管理无关。关闭套接字是实现所谓的优雅关闭协议,它允许通信双方实现连接正在关闭,并允许最小化数据丢失。