TCP入門與實例講解


內容簡介

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次揮手。

這里留幾個問題給讀者朋友:

  1. 建立連接的主要目的是什么?做了哪些事情?
  2. 建立連接為什么是3次握手,可不可以是2次?
  3. 斷開連接一定要4次揮手嗎?

Seq => Sequence Number,Ack => Acknowledgment Number,[SYN] => 控制標志SYN,[ACK] => 控制標志ACK

建立連接

一般情況下,握手流程如 下圖 所示,主要做了兩件事情:

  1. 互相確認對方當前可以建立連接
  2. 互相交換確認初始序列號(ISN)

斷開連接

一般情況下,TCP斷開連接需要4次揮手。假設 TCP A 主動斷開連接,流程如下。主要就是告知對方,自己准備斷開連接了,並且等待對方的確認。

從實例看TCP生命周期

在這一小節,會通過例子,闡述TCP從建立連接,到數據傳輸,到最后斷開連接的整個過程,並通過wireshark抓包探究一些通信的細節。

首先,打開wireshark監聽網絡請求。然后,在終端輸入如下命令發送HTTP請求。

curl http://id.qq.com/index.html

下面為wireshark抓包截圖,分為3個部分,分別為 (1)建立連接,(2)數據傳輸,(3)斷開連接。

tcp請求

建立連接

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)

Why do we need a 3-way handshake? Why not just 2-way?

原文地址:https://www.chyingp.com/posts/understanding-tcp/


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM