TCP 協議工作在OSI的傳輸層,是一種可靠的面向連接的數據流協議,TCP之所以可靠,是因為它保證了傳送數據包的順序。順序是用一個序列號來保證的。響應包內也包括一個序列號,表示接收方准備好這個序列號的包。在TCP傳送一個數據包時,它會把這個數據包放入重發隊列中,同時啟動計時器,如果收到了關於這個包的確認信息,便將此數據包從隊列中刪除,如果在計時器超時的時候仍然沒有收到確認信息,則需要重新發送該數據包。另外,TCP通過數據分段中的序列號來 保證所有傳輸的數據可以按照正常的順序進行重組,從而保障數據傳輸的完整。
在TCP通訊中主要有連接的建立、數據的傳輸、連接的關閉三個過程!每個過程完成不同的工作,而且序列號和確認號在每個過程中的變化都是不同的。
TCP會話的每一端都包含一個32位(bit)的序列號,該序列號被用來跟蹤該端發送的數據量。每一個包中都包含序列號,在接收端則通過確認號用來通知發送端數據成功接收。
TCP建立連接
TCP在其協議頭中使用大量的標志位或者說1位(bit)布爾域來控制連接狀態,一個包中有可以設置多個標志位。
TCP是主機對主機層的傳輸控制協議,提供可靠的連接服務,采用三次握手確認建立一個連接:
位碼即TCP標志位,有6種標示:SYN(synchronous建立聯機) ACK(acknowledgement 確認) PSH(push傳送) FIN(finish結束) RST(reset重置) URG(urgent緊急)Sequence number(順序號碼) Acknowledge number(確認號碼)
我們常用的是以下三個標志位:
-
-
SYN - 創建一個連接
-
FIN - 終結一個連接
-
ACK - 確認接收到的數據
-
握手過程
所謂三次握手(Three-way Handshake),是指建立一個TCP連接時,需要客戶端和服務器總共發送3個包。
三次握手的目的是連接服務器指定端口,建立TCP連接,並同步連接雙方的序列號和確認號並交換 TCP 窗口大小信息.在socket編程中,客戶端執行connect()時。將觸發三次握手。
1) 第1步 :客戶端向服務器發送一個同步數據包請求建立連接,該數據包中,初始序列號(ISN)是客戶端隨機產生的一個值,確認號是0;
2) 第2步 :服務器收到這個同步請求數據包后,會對客戶端進行一個同步確認。這個數據包中,序列號(ISN)是服務器隨機產生的一個值,確認號是客戶端的初始序列號+1;
3) 第3步 :客戶端收到這個同步確認數據包后,再對服務器進行一個確認。該數據包中,序列號是上一個同步請求數據包中的確認號值,確認號是服務器的初始序列號+1。
第一次握手:
客戶端發送一個TCP的SYN標志位置1的包指明客戶打算連接的服務器的端口,以及初始序號X,保存在包頭的序列號(Sequence Number)字段里。
第二次握手:
服務器發回確認包(ACK)應答。即SYN標志位和ACK標志位均為1同時,將確認序號(Acknowledgement Number)設置為客戶的I S N加1以.即X+1。
第三次握手:
客戶端再次發送確認包(ACK) SYN標志位為0,ACK標志位為1.並且把服務器發來ACK的序號字段+1,放在確定字段中發送給對方.並且在數據段放寫ISN的+1。
初始序列號(ISN)隨時間而變化的,而且不同的操作系統也會有不同的實現方式,所以每個連接的初始序列號是不同的。TCP連接兩端會在建立連接時,交互一些信息,如窗口大小、MSS等,以便為接着的數據傳輸做准備。
RFC793指出ISN可以看作是一個32bit的計數器,每4ms加1,這樣選擇序號的目的在於防止在網絡中被延遲的分組在以后被重復傳輸,而導致某個連接的一端對它作錯誤的判斷。
用wireshark抓包我們可以分析:以打開百度網站為例(115.239.211.112百度網站IP地址):
第一步:客戶端發送SYN標志:
SYN置位,初始序列號為0。
第二步:服務器應答:
SYN、ACK置位,確認序列號為客戶端ISN+1 。服務器發送序列號為0。
第三步:客戶端再發確認包
客戶端再次發送確認包(ACK) ,SYN標志位為0,ACK標志位為1.並且把服務器發來ACK的序號字段+1,放在確認字段中發送給對方。
TCP傳輸數據
在TCP建立連接后,就可以開始傳輸數據了。TCP工作在全雙工模式,它可以同時進行雙向數據傳輸。這里為了簡化,我們只談服務器向客戶端發送數據的情況,而客戶端向服務器發送數據的原理和它是類似的,這里便不重復說明。
服務器向客戶端發送一個數據包后,客戶端收到這個數據包后,會向服務器發送一個確認數據包。
傳輸數據的簡要過程如下:
1) 發送數據 :服務器向客戶端發送一個帶有數據的數據包,該數據包中的序列號和確認號與建立連接第三步的數據包中的序列號和確認號相同;
2) 確認收到 :客戶端收到該數據包,向服務器發送一個確認數據包,該數據包中,序列號是為上一個數據包中的確認號值,而確認號為服務器發送的上一個數據包中的序列號+所該數據包中所帶數據的大小。
數據分段中的序列號可以保證所有傳輸的數據按照正常的次序進行重組,而且通過確認保證數據傳輸的完整性。
TCP關閉連接
前面我們提到,建立一個連接需要3個步驟,但是關閉一個連接需要經過4個步驟。因為TCP連接是全雙工的工作模式,所以每個方向上需要單獨關閉。在TCP關 閉連接時,首先關閉的一方(即發送第一個終止數據包的)將執行主動關閉,而另一方(收到這個終止數據包的)再執行被動關閉。
關閉連接的4個步驟如下:
1) 第1步 :服務器完成它的數據發送任務后,會主動向客戶端發送一個終止數據包,以關閉在這個方向上的TCP連接。該數據包中,序列號為客戶端發送的上一個數據包中的確認號值,而確認號為服務器發送的上一個數據包中的序列號+該數據包所帶的數據的大小;
2) 第2步 :客戶端收到服務器發送的終止數據包后,將對服務器發送確認信息,以關閉該方向上的TCP連接。這時的數據包中,序列號為第1步中的確認號值,而確認號為第1步的數據包中的序列號+1;
3) 第3步 :同理,客戶端完成它的數據發送任務后,就也會向服務器發送一個終止數據包,以關閉在這個方向上的TCP連接,該數據包中,序列號為服務器發送的上一個數據包中的確認號值,而確認號為客戶端發送的上一個數據包中的序列號+該數據包所帶數據的大小;
4) 第4步 :服務器收到客戶端發送的終止數據包后,將對客戶端發送確認信息,以關閉該方向上的TCP連接。這時在數據包中,序列號為第3步中的確認號值,而確認號為第3步數據包中的序列號+1;
注意 : 因為FIN和SYN一樣,也要占一個序號。理論上服務器在TCP連接關閉時發送的終止數據包中,只有終止位是置1,然后客戶端進行確認。但是在實際的 TCP實現中,在終止數據包中,確認位和終止位是同時置為1的,確認位置為1表示對最后一次傳輸的數據進行確認,終止位置為1表示關閉該方向的TCP連接。