1. 程式人生 > >socket連結的關閉close和shutdown的區別

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包。
另外:對於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衝突的概率更大。