內容簡介
TCP是TCP/IP協議棧的核心組成之一,對開發者來說,學習、掌握TCP非常重要。
本文主要內容包括:什么是TCP,為什么要學習TCP,TCP協議格式,通過實例講解TCP的生命周期(建立連接、傳輸數據、斷開連接)
TCP簡介
傳輸層控制協議(Transport Control Protocol),TCP/IP協議棧的核心之一。位於應用層與網絡層之間,提供面向連接的、可靠的字節流服務。
記住關鍵詞“面向連接”、“可靠”、“字節流”,這是學習掌握TCP的關鍵:
- 面向連接:客戶端、服務端交換數據前,需要建立連接;
- 可靠:通過特定機制,在不可靠的網絡之上,確保報文准確送達,
- 字節流:數據的最小單位為字節。至於字節中存儲內容的含義,由於應用層的程序決定。
TCP如何確保服務可靠性
TCP花了大量的功夫在確保傳輸層服務的可靠性上,具體舉措包括(但不限於)以下:
- 應用數據切割:應用數據被分隔成TCP認為最適合發送的多個報文段(由特定的算法和機制來確認)
- 接收端確認:接收端收到報文段后,會向發送端發送確認報文;
- 超時重傳機制:發送端發送一個報文段后,會啟動定時器,等待接收端確認收到這個報文;如果沒有及時收到確認,發送端會重新發送報文;
- 數據校驗和:發送端發送的報文首部中,有個叫做校驗和(checksum)的特殊字段,它是根據報文的首部、數據計算出來的。這是一個端到端的校驗和,用來檢測傳輸過程數據的變化。接收端收到報文后會對校驗和進行檢查,如果校驗和存在差錯,則丟棄這個報文,且不確認收到此報文(等待發送端超時重發)
- 報文段排序:TCP報文包裹在IP數據包里進行傳輸,而IP數據包的到達次序是不固定的。接收端會對接收到的報文段重新排序,這個對應用層是無感知的;
- 去重復:接收端丟棄重復的報文(比如,因某些原因,雖然接收端已經收到報文,且給發送端發送了接收確認,但接收端沒有收到該確認,超時后重新發送了同樣的報文);
- 流量控制:TCP連接雙方都有固定大小的緩沖空間,且只允許發送端發送緩沖空間能夠容納的數據,避免緩沖區溢出;
TCP傳輸服務的可靠性對應用層的開發者來說至關重要。作為應用層的開發者(比如HTTP server),除了業務邏輯之外,如果還需要操心數據是否正常送達,接收到的數據是否完整,開發效率會相當低下。
參考自《TCP/IP詳解卷一》,推薦閱讀
TCP首部格式
TCP首部格式如下圖所示,在不包含可選字段的情況下,大小通常為20個字節。部分字段定義可能並不直觀,如果讀者覺得某些首部字段不好理解,建議先跳過,結合后文的實例可能更容易理解些。
比如 Sequence Number/Acknowledgment Number/ACK/SYN,結合TCP建立連接的過程來看,會更好理解。
這里留個小問題給讀者:怎么知道TCP報文段數據(data)的長度是多少?
Source Port(來源端口):16位
Destination Port(目的端口):16位
Sequence Number(序號):32位
TCP報文段中的數據部分,每一個字節都有它的序號(遞增)。根據控制標志(Control Bits)中的SYN是否為1,Sequence Number 表達不同的含義:
- SYN = 1:當前為連接建立階段,此時的序號為初始序號(ISN)。當數據傳輸正式開始時,數據的第一個字節的序號為 ISN + 1;
- SYN = 0:當前報文段中,數據部分的第一個字節的序號。
Acknowledgment Number(確認序號):32位
當控制標志的ACK為1時,表示發送方希望收到的下一個報文段的序號(Sequence Number)。一旦連接建立成功,ACK值一直為1。
Data Offset(數據偏移量):4位
TCP報文段的首部長度,單位是word(4字節)。字面含義是:TCP報文段的數據的起始處,距離TCP報文段的起始處 的偏移量。4個字節最大能表示的數字是15,所以首部最大60字節。
Reserved(保留字段):6位
預留作為后續用途,必須是0。
Control Bits(控制標志):6位
一共有6個控制標志,其中SYN/ACK、FIN/ACK主要用於連接的建立、斷開階段。
- URG: 當置為1時,表示緊急指針(Urgent Pointer)字段有效;
- ACK: 確認序號字段(Acknowledgment Number)有效;
- PSH: 接收方應立即把這個報文段交給應用層;
- RST: 重建連接;
- SYN: 同步序號,用於建立連接;
- FIN: 發送端不再發送數據;
Window Size(窗口大小):16位
允許對方發送的數據量。告訴對方自己緩沖區還能容納多少字節,用來控制對方發送數據的速度。
比如,服務端發送給客戶端的TCP報文段中,確認序號是701,窗口字段(Window Size)是1000,表明服務端能夠接受客戶端發來的,序號從701開始的1000字節數據。
Checksum(校驗和):16位
發送端對TCP首部、數據進行CRC運算得出的結果。接收端收到數據后,對接收到的TCP報文段的首部、數據進行CRC運算,並跟TCP首部中的校驗和進行對比,確保數據在傳輸過程中沒有損壞。
計算、校驗規則這里先不展開。
Urgent Pointer(緊急指針):16位
僅在URG=1時才生效,它的值是一個偏移量,和序號字段中的值相加得到緊急數據最后一個字節的序號。
options(可選字段):大小不固定
最常見的可選字段是MSS(Maximum Segment Size),表示最長報文大小,通信雙方通常在連接的第一個報文段中指明這個選項。(只能出現在SYN報文中)
建立連接 vs 斷開連接
TCP的兩段正式開始傳輸數據前,需要先建立連接。一旦數據傳輸完成,則需要斷開連接。
后面章節中,會通過實際例子說明TCP數據傳輸的完整生命流程。在這之前,先簡單介紹下TCP是如何建立連接以及斷開連接的,也就是我們所熟悉的3次握手以及4次揮手。
這里留幾個問題給讀者朋友:
- 建立連接的主要目的是什么?做了哪些事情?
- 建立連接為什么是3次握手,可不可以是2次?
- 斷開連接一定要4次揮手嗎?
Seq => Sequence Number,Ack => Acknowledgment Number,[SYN] => 控制標志SYN,[ACK] => 控制標志ACK
建立連接
一般情況下,握手流程如 下圖 所示,主要做了兩件事情:
- 互相確認對方當前可以建立連接
- 互相交換確認初始序列號(ISN)
斷開連接
一般情況下,TCP斷開連接需要4次揮手。假設 TCP A 主動斷開連接,流程如下。主要就是告知對方,自己准備斷開連接了,並且等待對方的確認。
從實例看TCP生命周期
在這一小節,會通過例子,闡述TCP從建立連接,到數據傳輸,到最后斷開連接的整個過程,並通過wireshark抓包探究一些通信的細節。
首先,打開wireshark監聽網絡請求。然后,在終端輸入如下命令發送HTTP請求。
curl http://id.qq.com/index.html
下面為wireshark抓包截圖,分為3個部分,分別為 (1)建立連接,(2)數據傳輸,(3)斷開連接。
建立連接
1、本地 -> 服務端:[SYN] Seq=0;
備注:本例子中中,客戶端、服務端的初始Seq值其實不是0,截圖中展示的0是個相對值,是wireshark為了方便開發者進行抓包分析轉化過來的。
2、服務端 -> 本地:[SYN, ACK] Seq=0, Ack=1;
3、本地 -> 服務端:[ACK] Seq=1, Ack=1
到這里,雙方連接建立,開始交換數據
數據傳輸
數據交換是雙向的,這里以服務端的HTTP響應為例子。響應內容較大,被拆成了多個TCP包。整個數據發送的過程,就是服務端向客戶端發送數據,客戶端向服務端發送確認的過程。
1.1、服務端->客戶端:Seq=1,TCP數據長度273。也就是說,服務端發送的報文段中,第一個數據字節的序號是1;下一個TCP報文段,第一個數據字節的序號應該是274。
1.2、客戶端->服務端:Ack=274。表示客戶端已經收到序號274之前的所有字節;也就是說,服務端如果繼續給客戶端發送TCP報文,應該發送序號274及以后的數據。
2.1、服務端->客戶端:Seq=274,TCP數據長度1400。也就是說,服務端發送的報文段中,第一個數據字節的序號是274;下一個TCP報文段,第一個數據字節的序號應該是1674(274 + 1400)。
2.2、。。。
后面的分析過程同上。
斷開連接
從抓包中看到比較有意思的點。當服務端收到客戶端的斷開請求時(FIN=1),服務端在同一個響應包里發送了FIN、ACK,達到了減少一個數據包的效果。
為什么要學習TCP
筆者在前端招聘的面試中,經常會問一些網絡基礎方面的問題,經常會有面試者感到困惑:為什么要問這些問題?這些知識是他們需要掌握的嗎?好像跟工作關聯不大?
這可能是普遍的誤區。
掌握HTTP協議的重要性不用強調,WEB開發者的基礎要求之一。但是,有必要學習TCP嗎?這個問題倒是值得思考一下。
答案是:很有必要。
舉個例子:
WebSocket是基於TCP的,並復用了HTTP的握手通道。如果開發者對HTTP、TCP沒有一定的了解,那么在使用WebSocket的時候,WebSocket對他來說就像一個黑盒,充滿了各種黑科技。WebSocket、HTTP兩者有什么關聯?WebSocket跟Socket.io有什么關聯?為什么服務端開啟多個Socket.io實例,並通過反向代理進行轉發后,連接握手就會失敗?
如果開發者對HTTP、TCP足夠了解,在遇到上面的問題時,就不至於毫無頭緒。
再舉個例子:
在探究性能優化時,經常會提到HTTP/2。什么是HTTP/2,為什么說HTTP/2的性能比HTTP 1.1好?什么是HTTP/2的多路復用?是怎么實現的?有什么好處?
同樣的,如果對HTTP、TCP足夠了解,上面的問題並不難回答,翻翻書或協議,至少能夠回答個大概。
寫在后面
TCP/IP由復雜的協議棧組成,而TCP是協議棧中的核心部分。TCP協議本身非常復雜,本文只是對基礎部分進行了講解,還有許多內容尚未覆蓋到,比如TCP的超時重傳機制、擁塞控制機制等,后面有時間再繼續展開。
如有錯漏,敬請指出。
相關鏈接
《TCP/IP詳解卷一》
Difference between push and urgent flags in TCP
Calculate size and start of TCP packet data (excluding header)