TCP 用三個分節建立一個連接,終止一個連接則需要四個分節。
1. 某個應用進程首先調用 close,我們稱這一端為執行主動關閉的一端,這一端TCP 發送一個FIN分節 FIN K,標是數據發送完畢。
2. 接收 到FIN的另一端執行被動關閉,這個FIN 由 tcp 確認 ack k + 1,他的接收也作為文件結束符傳輸給接收方應用進程,因為FIN的接收意味著應用進程在相應連接上再也接收不到額外數據。
3. 一段時間后,接收到文件結束符的應用進程將調用close關閉他的套接口,這導致它的tcp 也發送一個FIN, FIN J.
4. 接收到這個FIN的原發送方 TCP對他進程確認 ack j+1.
因為每個方向都要有一個FIN 和一個ACK, 所以一般需要四個分節,我們用限定詞一般是因為有時步驟1的FIN 隨數據一起發送,另外,執行被動關閉的那一端tcp在步驟2和3發出的ACK與FIN也可以合并成一個分節。
FIN占據一個字節的序列號空間,這與SYN相同,所以每個FIN的ACK是這個FIN的序列號加1.
在步驟2和3之間可以有從執行被動關閉端到執行主動關閉端的數據流,這稱為半關閉(half-close),套接口關閉時每一端都要發送一個FIN,這種情況在應用進程調用close時會發生,但在進程終止時所有打開的描述符句柄將自動關閉,此時仍然打開的tcp鏈接也會發出一個FIN.
在連接關閉前,兩端進程的tcp都處于ESTABLISHED狀態,如果這時進程主動調用close(主動發起端),則發出FIN 分節,自身轉換到FIN_WAIT_!狀態,接收到FIN分節的對端則從ESTABLISH狀態轉換到 CLOSE_WAIT狀態并發出ACK 給發出FIN端確認,然后從CLOSE_WAIT狀態轉換到 LAST_ACK,執行主動關閉的一端在收到對端的ACK時從FIN_WAIT_1 轉換到FIN_WAIT_2等待對端發FIN分節,收到FIN分節后則從FIN_WAIT_2狀態轉換到TIME_WAIT狀態并發送FIN 的ACK給對端,執行被動關閉的一端在收到ACK后從LAST_ACK狀態轉換到CLOSED狀態,我們發現,主動發起關閉的一端進入TIME_WAIT狀態,此狀態是關于TCP網絡編程中最難理解的部分,下一篇繼續分析此部分。
不論是建立tcp 鏈接還是終止連接,都是在各個狀態間的轉換,一個tcp鏈接有11種狀態,并且規定了如何基于當前狀態及在該狀態下所接收的分節從一個狀態轉換到另一個狀態,比如當進程在 closed狀態下執行主動打開時(connect),tcp將發送一個SYN分節,并從closed狀態轉換到 SYN_SEND狀態,如果該tcp 接收到一個帶有ACK 的SYN,他將發送一個ACK并轉換成ESTABLISHED狀態,這個狀態是數據傳送狀態。tcp協議棧在實現過程中是用一個有限狀態機(FSM)來管理這些狀態的流轉。
一個工具,查看系統中處于各個狀態的個數:
#netstat -an|awk '/tcp/ {print $6}'|sort|uniq -c