聊聊TCP協議

TCP報文可以說是最常見的報文之一,但TCP具體的工作原理了解的人卻不多,在這裡展開來說一說這個TCP協議,了解比較深或者想要完整了解這個協議的朋友可以直接去查閱RFC793,本文只是盡量寫一些TCP比較重要的功能及實現,遠遠達不到全面、準確這兩點。

簡介

TCP = TRANSMISSION CONTROL PROTOCOL,即傳輸控制協議。

在網路中,TCP協議處於第四層,在物理層(線纜,光纖,無線信道等),數據鏈路層(交換層面segment),網路層(IP)這三個層面之上的一層協議。也就是說,在我們討論TCP協議的時候,意味著我們的前提是IP可達,ping包可通的情況下。

那為什麼要設計TCP協議呢?因為實際需求就在那裡,好吧我來翻譯這句話。

首先我們知道,需要給兩台設備設計的通信有很多很多,比方說你要上傳/下載文件,發送QQ消息,發送郵件等等,如果把這些協議都設計成三層,那麼IP協議將會十分複雜且低效。所以我們新增了四層埠號這個概念,將網路拓展到了四層。這時候兩種聲音出現了,一種聲音是可靠傳輸,但會損失一些性能;另一種聲音是不需要可靠傳輸,要的是更低的延遲,更精簡的包頭。因為有這兩種不同的需求,所以TCP和UDP兩種協議便被設計並規範出來。可以說TCP是為了滿足多樣,可靠的傳輸而出現的產物。

包頭

當我們談及網路協議時,最簡單的方法就是看它的包頭,如果能深刻的理解包頭每個位元組的作用,那麼你也就真正的理解了這種網路協議。不多說,上圖。

前文已經說過,TCP協議設計出來的主要目的是為了滿足多樣、可靠這兩種需求。圖中的前三行,4個欄位,共12個位元組很好的解釋了這一點。

Source Port & Destination Port: 16 bits*2

源埠和目的埠各佔16 bits,也就是說我們可以擁有2^16 = 65536個埠號,也就是說我們可以開放這6萬多個埠給一台設備提供不同的服務。

Sequence Number & Acknowledgment Number: 32 bits*2

這兩個欄位各自佔據了TCP包頭4個位元組的位置,其重要性可想而知,而且TCP的可靠傳輸主要是靠這兩個位元組來實現,具體它們是如何實現在工作這一小節去具體描述。再往下看。

Data Offset: 4 bits

因為TCP包頭中有部分可選欄位,所以我們需要一個指針來指示數據的開始的地方,Data Offset欄位完成的就是這頂功能。有細心的同學會發現,它的最大值為2^4 = 16,而圖中的TCP包頭已經有24個位元組了,這裡要特殊說明的是,這裡的1是代表1行,也就是4個位元組的內容,我們可以表示的範圍是(0 ~ 15)*4 = 0 ~ 60位元組,而TCP最少佔有20個位元組,這就意味著我們最多有40個位元組的可選欄位可以使用。

Reserved: 6 bits

這是保留欄位,不用時設為0。或許當我們需要實現新的功能時,這6個bit可以提供相應的標識。目前後三個bit已經有用作標識,NS、CWR、ECE,有興趣的同學可以自己去看看相關RFC的規定。

Control Bits: 6 bits

URG: Urgent Pointer field significant

確認是否有緊急指針,即第五行後面的Urgent Pointer欄位。

ACK: Acknowledgment field significant

確認是否為ACK信息,除了初始的SYN包外,這個欄位都應標為1。

PSH: Push Function

確認是否將數據推給上層協議,如果是1則推送,如果是0則先緩存下來。

RST: Reset the connection

確認是否重置連接,如果出現重大差錯,會將該欄位置為1。

SYN: Synchronize sequence numbers

確認是否為同步序列號,只有從端發出的第一個包才會將該該置為1.

FIN: No more data from sender

確認是否中斷。如果發送方將信息發送完畢則將該欄位置為1。

Window: 16 bits

表示從確認號開始,本報文的源方可以接收的位元組數,即源方接收窗口大小。這是個很有意思的機制,有機會再展開討論一下。

Checksum: 16 bits

對整個的TCP報文段,包括TCP頭部和TCP數據,以16位字進行計算所得。該欄位主要確認在信道傳輸過程中,內容無差錯。

Urgent Pointer: 16 bits

用作指針,指到緊急數據的結束位。主要用途是傳輸一些緊急數據,這裡不展開說了。

Options & Padding

擴展欄位,前文已經計算過,最長為40個位元組,這裡也不展開說了。

Data

數據,前面那麼多包頭的信息,傳輸的就是這數據,研究協議的時候,我們把他看作成一個整體就好,不用關心我們到底利用這個協議傳輸了什麼內容。至於MTU長度,分片等內容也很重要,有時間再寫吧。

工作原理

因為不能把所有的IP協議都當作TCP協議來使用,所以我們規定,當檢測到IP協議中PROTOCOL欄位為6時,我們將IP欄位後的協議視為TCP協議。也就是說,我們討論的前提又加了一項,TCP協議被調用。

TCP的功能有很多很多,在這裡選擇介紹兩項關注比較多的內容,連接建立/斷開和流量控制。如果一起討論其它功能,可以在評論區留言說明。

連接建立/斷開

一個正常的TCP連接從建立到分開,要完成三次握手四次揮手。先是建立,見圖。

  1. 客戶端向伺服器申請建立TCP連接,向伺服器端發送一個SYN報文,作為第一次握手。客戶端把這段連接的SYN設定為隨機數A。
  2. 伺服器端收到SYN報文後,會給客戶端發送一個報文。報文中ACK的確認碼為A+1,同時發送另一個SYN為隨機序號B。
  3. 此時,客戶端收到ACK為A+1的報文,將之與發送的SYN包進行比對,如果滿足+1的關係,則在客戶端判斷連接已建立。並給伺服器發送確認數據包,SYN為A+1,表明已收到上一報文,ACK為B+1,通知伺服器進入連接狀態。

至此,TCP連接建立完畢,可以正常傳輸數據了。再是連接終結,即四次揮手,還是看圖。

終結連接操作可由雙方任意一方發起。本文以客戶端發起為例。

  1. 客戶端向伺服器端發送一個FIN報文,作為第一次揮手。通知伺服器,我已經沒有數據還要發送。但不確認伺服器是否扔有數據返回,所以連接仍是建立狀態。
  2. 伺服器收到FIN報文,返回一個ACK報文,告訴客戶端,我知道你已經沒有東西要發送了,但我還要再確認一下我是不是還有東西要給你。
  3. 伺服器判斷自己也沒有報文需要發送給客戶端,發送FIN消息,告訴客戶端,好了,這下我也沒有東西要給你了,你可以終結連接了。此時伺服器不確認客戶端是否收到信息,繼續保持連接。
  4. 客戶機收到ACK和FIN消息後,得知伺服器已經知道自己要終結,並且無更新內容,便給伺服器發送一個ACK說我知道了,你也終結吧,客戶機便終結連接。伺服器在收到最後一條ACK後,也終結連接。

至此,四次揮手操作完成,連接終結。

擁塞控制

要注意的是,擁塞控制和流量控制不是一回事,今天要說的是擁塞控制,流量控制有機會再聊。擁塞控制是TCP協議設計中一個很棒的特性,這個特性讓TCP協議在網路傳輸中合理的利用帶寬,使速度最大化。TCP中的擁塞控制用到以下幾種技術,慢啟動、擁塞避免、快速重傳和快速恢復技術。

慢啟動技術。如果連接建立好,一上來就給對端發大量的報文,可能無法到達,並造成網路鏈路的擁塞。慢啟動技術是開始會發很小的報文給對端,收到對端的ACK判斷可達後,會加倍報文量發送同時等待,如果收到對端的ACK則繼續加倍,如果等待超時且沒有收到ACK則意味著報文過大,超過鏈路負荷,開始發送原有報文+1大小的報文,如此反覆。以達到最大利用帶寬。

可以說,慢啟動是擁塞控制技術的核心。但如果在傳輸中遇到了鏈路不穩定,TCP則會讓傳輸速度降至谷底,將窗口設為1,繼續慢啟動。這樣,一個小小的干擾就讓速度損失這麼多,並且浪費了帶寬,IT人肯定是不同意的,所以就有了後面幾種機制。這麼多的技術,其目的只有一個,儘可能大的利用帶寬!抓住這一點再對後面的技術產生和原理進行理解,將事半功倍。這裡就不再展開繼續說明了。

總之,這次寫了不少東西,也挖了不少坑,具體要不要填,填哪些坑,希望和朋友們一起探討,歡迎大家留言。

最後,貼一下TCP完整的邏輯判斷及狀態機流程圖,如果能看懂這張圖以及上面的報文圖。可以說你已經對TCP有了一個較深的理解了。

參考

本文部分內容,引用自Wikipedia和相關RFC,有興趣深入了解的朋友也可以自行查看。

TCP維基百科

TRANSMISSION CONTROL PROTOCOL

TCP Extensions for High Performance

推薦閱讀:

TAG:计算机网络 | 网络工程师 | 网络协议 |