Linux 下TCP鏈接關閉狀況分析

1、TCP鏈接關閉的幾種方式:shell

一、「正常」關閉:調用close()關閉socket、沒close但進程正常結束(固然這是不該該的作法)、進程core掉、在shell命令 行中kill掉進程,均可抽象成「正常」關閉。由於即便core掉,內核也會立刻幫應用程序回收(close)socket文件描述符。服務器

     「正常」關閉,默認狀況下(非默認即設置Linger下面會介紹),關閉端即客戶端TCP層會發FIN包,對端即服務器TCP層收到後,回ACK,客戶端 進入FIN_WAIT2狀態。此時,TCP終止鏈接的4個分組中服務器應該發的第3個分組FIN包,其TCP層是不會主動發的,只有服務器端socket 「正常」關閉,纔會發出這個FIN包。至此,客戶端進入TIME_WAIT狀態。併發

二、「非」正常關閉:客戶端崩潰了,此時確定發不出FIN包了(固然啦,內核都沒機會幫應用程序回收資源了)。這種狀況,服務器端有以下兩種狀況:socket

    A、服務器send數據,由於客戶端已經崩潰,服務器收不到ACK天然會不停的重傳。源自tcp

        Berkeley的重傳機制,重傳8次,相對第一次傳的15分鐘後仍沒收到ACK,則返回函數

        ETIMEDOUT或EHOSTUNREAC錯誤。若是服務器不理會這個錯誤,再次調用send,則spa

        立馬返回Broken Pipe錯誤。    orm

       注:15分鐘超時能夠在 /proc/sys/net/ipv4/tcp_retries2 中修改接口

   B、 服務器不發任何數據了,那只有靠應用層心跳檢測機制或Keepalive,來發覺TCP斷連了。進程

2、SO_LINGER套接口選項

           A、l_onoff設置爲0,這也是默認狀況,函數close()是當即返回的,而後TCP鏈接雙方是經過

                FIN、ACK4分組來終止TCP鏈接的。固然,發送緩衝區還有數據的話,系統將試着將這些數據

                發送到對方。

           B、l_onoff非0,l_linger設置0,函數close()當即返回,併發送RST終止鏈接,發送緩衝區的數據丟棄。

           C、l_onoff非0,l_linger非0,函數close()不當即返回,而是在(a)發送緩衝區數據發送完並獲得確認

                 (b)l_linger延遲時間到,l_linger時間單位爲微妙。二者之一成立時返回。若是在發送緩衝區數據發送

                完並被確認前延遲時間到的話,close返回EWOULDBLOCK(或EAGAIN)錯誤。

3、客戶端TCP鏈接「正常」關閉,服務器的幾種狀況:

          情形 客戶端l_onoff設置爲0, 
「正常」關閉
客戶端l_onoff非0,l_linger設置0,「正常」關閉
服務器阻塞模式send,正阻塞在send函數未返回 客戶端TCP發送FIN,服務器send函數返回成功(返回字節數是實際拷貝到發送緩衝區的字節數)。客戶端發送RST。若是服務器再次調用send,將返回errno[32]:Broken pipe 客戶端TCP發送RST,服務器函數返回成功(返回字節數是實際拷貝到發送緩衝區的字節 數)。若服務器再次調用send,則返回-1,errno[104]:Connection reset by peer。若再次調用send,則返回-1,errno[32]:Broken pipe
服務器空閒 客戶端TCP發送FIN,若服務器沒理會而調用send,客戶端發送RST,send返回-1,errno[32]:Broken pipe 客戶端TCP發送RST,若服務器沒理會而調用send,send返回-1,errno[104]:Connection reset by peer。若再次調用send,則返回-1,errno[32]:Broken pipe

 

總之,一、收到對端RST後,仍然調入send(),則返回Connection reset by peer,再次調用send(),則返回Broken pipe

         二、收到對端FIN後,仍然調研哪一個send(),直接返回Broken pipe

相關文章
相關標籤/搜索