TCP如何能正常关闭连接?
一、TCP連接關閉的幾種方式:
1、“正常”關閉:調用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狀態。
2、“非”正常關閉:客戶端崩潰了,此時肯定發不出FIN包了(當然啦,內核都沒機會幫應用程序回收資源了)。這種情況,服務器端有如下兩種情況:
??? A、服務器send數據,因為客戶端已經崩潰,服務器收不到ACK自然會不停的重傳。源自
??????? Berkeley的重傳機制,重傳8次,相對第一次傳的15分鐘后仍沒收到ACK,則返回
??????? ETIMEDOUT或EHOSTUNREAC錯誤。如果服務器不理會這個錯誤,再次調用send,則
??????? 立馬返回Broken Pipe錯誤。?????
?????? 注:15分鐘超時可以在 /proc/sys/net/ipv4/tcp_retries2 中修改
?? B、 服務器不發任何數據了,那只有靠應用層心跳檢測機制或Keepalive,來發覺TCP斷連了。
二、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)錯誤。
三、客戶端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 |
?
總之,1、收到對端RST后,仍然調入send(),則返回Connection reset by peer,再次調用send(),則返回Broken pipe
???????? 2、收到對端FIN后,仍然調研哪個send(),直接返回Broken pipe
總結
以上是生活随笔為你收集整理的TCP如何能正常关闭连接?的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: TCP关闭
- 下一篇: IPIP地址、ipv4ipv6、子网掩码