socket链接的关闭连接与close和shutdown的区别

Posted wangshaowei

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了socket链接的关闭连接与close和shutdown的区别相关的知识,希望对你有一定的参考价值。

TCP主动关闭连接 
appl: close(),  --> FIN     FIN_WAIT_1 //主动关闭socket方,调用close关闭socket,发FIN                         
                <-- ACK     FIN_WAIT_2 //对方操作系统的TCP层,给ACK响应。然后给FIN                  
                <-- FIN                  
                --> ACK     "TIME_WAIT"   -- 2MSL timeout -->CLOSED
                                        //TIME_WAIT,防止ACK没有给到对方。
注意:close时,如果TCP发送队列中还有数据,那么将会发送RST包而不是FIN包。
参看:http://rdc.taobao.com/blog/cs/?p=1055
另外:对于Linux下来说,无论是FIN还是RST,应用层read将会返回0,可以认为对方请求关闭链接,调用close关闭fd即可。
TCP被动关闭连接 
            <-- FIN     "CLOSE_WAIT"   //被动方,收到对方的FIN,处于CLOSE_WAIT状态                  
                --> ACK                    //被动方的TCP层,给ACK响应  
                appl: close(),  --> FIN     LAST_ACK      
                                         //被动方调用close,从CLOSE_WAIT转到LAST_ACK
                                         不调close,将一直在CLOSE_WAIT状态。                 
                 <-- ACK         --> CLOSED  
tcp是全双工::
   close()会关闭读写。
   shutdown()可以选择性的关闭读、写或读写。 
 
  主动关系SOCKET链接的一方,会进入TIME_WAIT(作用是防止最后一个ACK包丢失)
   TIME_WAIT的时间会非常长,因此server尽量减少主动关闭连接。
 
close和shutdown的区别:
   int close(int sockfd);   

   close(fd)调用会将描述字的引用计数减1,只有当socket描述符的引用计数为0时,才关闭socket,即发送FIN包,因此,在fork()模式中,父进程在accept()返回后,fork()子进程,由子进程处理connfd,而父进程将close(connfd);由于connfd这个socket描述符的引用计数不为0,因此并不引发FIN,所以就没有关闭和客户端的连接。  

  int shutdown(int sockfd, int howto);    
  // howto: SHUT_RD, SHUT_WR, SHUT_RDWR  
  shutdown()则不管socket描述符的引用计数,而直接发生FIN,因此会直接关闭链接。 
  shutdown()可控制read/write两个方向的管道。 
   SHUT_RD     shutdown(sockfd, SHUT_RD);后,来自对端的数据都被确认,然后悄然丢弃。       
   SHUT_WR     half close状态。  
close()引发的4次交互:(这里的close是client发起的) 
            client                             server  
               FIN_WAIT_1   ---- FIN M ------>       
                                       //(Server端操作系统的TCP层(网络协议栈)响应ACK包)           
               FIN_WAIT_2   <---- ACK M+1----   CLOSE_WAIT
                                       //(这里必须调用close,才能从CLOSE_WAIT到LAST_ACK)                  
               TIME_WAIT    <------ FIN N -----  LAST_ACK 
                                        //(TIME_WAIT有一个重要的作用就是防止最后一个ACK丢失)           
                            ------- ACK N+1 ---->  CLOSE  
 

        

 TIME_WAIT 是主动关闭链接时形成的,等待2MSL时间,约4分钟。

         主要是防止最后一个ACK丢失。  由于time_wait的时间会非常长,因此server端应尽量减少主动关闭连接

 

CLOSE_WAIT是被动关闭链接是形成的 ,

        按状态机,我方收到FIN,则由TCP实现发送ACK,因此进入CLOSE_WAIT状态。

        但如果我方不执行close(),就不能由CLOSE_WAIT迁移到LAST_ACK,则系统中会存在很多CLOSE_WAIT状态的连接。

此时,可能是系统忙于处理读、写操作,而未将已收到FIN的连接,进行close。此时,recv/read已收到FIN的连接socket,会返回0。

 

大量TIME_WAIT和CLOSE_WAIT的存在,会产生怎样的影响?

        内核维护更多的状态。收到ip包,做hash运算,hlist冲突的概率更大。

 

另附一篇关于断开讲解很详细的文章

https://www.cnblogs.com/felixzh/p/8359066.html

以上是关于socket链接的关闭连接与close和shutdown的区别的主要内容,如果未能解决你的问题,请参考以下文章

socket websocket

怎么在服务器端关闭websocket连接

关于关闭 Socket 的一些坑

C# socket 如何断开连接

怎样判定socket连接已经关闭

jmeter压测时出现socket close关闭的问题