說起TCP,我們一般都需要知道發起一個tcp連接和終止一個tcp連接是所發生的事情,下邊,我將跟大家介紹下tcp的三次握手及四次揮手的過程。
TCP三路握手
(1)服務器必須准備好接受外來的連接。這通常在調用socket,bind,listen這三個函數來完成,我們稱之為被動打開(passive open)。
(2)客戶通過調用socket,connect發起主動打開(active open)。這導致客戶tcp發送一個SYN(同步)分節,它告訴服務器客戶將在待建立的tcp連接中發送數據的初始序列號。通常SYN分節不攜帶數據,其所在的IP數據報只包含有一個IP首部、一個TCP首部及可能有的TCP選項。
(3)服務器必須確認(ACK)客戶的SYN,同時自己也得發送一個SYN分節,它含有服務器將在同一連接中發送的數據的初始序列號。服務器在單個分節中發送SYN和對客戶SYN的ACK(確認)。
(4)客戶必須確認服務器的SYN。
這種交換至少需要三個分組,因此稱之為TCP的三路握手,如圖1:
圖1
TCP四路揮手
TCP建立一個連接需要3個分節,而終止一個連接一般需要4個分節,所以一般也稱為四路揮手。
(1)某個應用進程首先調用close,我們稱為該端執行主動關閉(active close),該端的tcp於是發送一個FIN分節,表示數據發送完畢。
(2)接收到這個FIN的對端執行被動關閉(passive close)。這個FIN由tcp確認。它的接受也作為一個文件結束符傳遞給接收端的應用進程(放在已排隊等候該應用進程接受的任何其他數據之后),因為FIN的接受意味着接收端應用進程在相應的連接上再無額外數據可接受。
(3)一段時間后,接受到這個文件結束符的應用進程將調用close關閉它的套接字。這導致它的tcp也發送一個FIN分節。
注:為什么是需要一段時候后,我的理解是由於接收到的fin分節作為一個文件結束符放在已排隊等候應用進程接受的所有數據之后,而應用進程調用read讀取數據得等它把這個文件描述符之前的所有數據讀取完后,才能讀取到該文件描述符,此時read返回0, 所以此時應用進程才知道對端已關閉了套接字,進而它也調用close關閉i套接字。
(4)接受這個最終FIN的原發送端tcp(即執行主動關閉的那一端)確認這個FIN。
如圖2展示的這些分組:
圖2
TCP連接發起和終止時套接字的狀態
tcp為一個連接定義了11中狀態,並且tcp規定如何基於當前狀態及在該狀態下所接收的分節從一個狀態轉換到另一個狀態。下邊我們通過圖3來展示tcp連接的分組交換情況及tcp套接字的狀態:
圖3
一旦建立一個連接,客戶就構造一個請求並發送給服務器。服務器處理該請求並發送一個應答,需要注意的是,服務器對客戶請求的確認是伴隨器應答發送的。這種做法稱為捎帶(piggybacking),它通常在服務器處理請求並產生應答的時間少於200ms時發生。如果服務器耗用更長時間,如1s,那么我們將看到先是確認后是應答。
接下來展示了終止tcp連接時交換的4個分節,從圖中我們可以看到,發送一個單分節請求和接受一個單分節的應答,使用tcp至少需要8個分節的開銷;如果改用udp,那么只需要交換兩個分組:一個承載請求,一個承載應答。不過從tcp切換到udp也失去了tcp提供給應用進程的全部可靠性,迫使應用進程來做可靠性處理。