聊聊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連接從建立到分開,要完成三次握手四次揮手。先是建立,見圖。
- 客戶端向伺服器申請建立TCP連接,向伺服器端發送一個SYN報文,作為第一次握手。客戶端把這段連接的SYN設定為隨機數A。
- 伺服器端收到SYN報文後,會給客戶端發送一個報文。報文中ACK的確認碼為A+1,同時發送另一個SYN為隨機序號B。
- 此時,客戶端收到ACK為A+1的報文,將之與發送的SYN包進行比對,如果滿足+1的關係,則在客戶端判斷連接已建立。並給伺服器發送確認數據包,SYN為A+1,表明已收到上一報文,ACK為B+1,通知伺服器進入連接狀態。
至此,TCP連接建立完畢,可以正常傳輸數據了。再是連接終結,即四次揮手,還是看圖。
終結連接操作可由雙方任意一方發起。本文以客戶端發起為例。- 客戶端向伺服器端發送一個FIN報文,作為第一次揮手。通知伺服器,我已經沒有數據還要發送。但不確認伺服器是否扔有數據返回,所以連接仍是建立狀態。
- 伺服器收到FIN報文,返回一個ACK報文,告訴客戶端,我知道你已經沒有東西要發送了,但我還要再確認一下我是不是還有東西要給你。
- 伺服器判斷自己也沒有報文需要發送給客戶端,發送FIN消息,告訴客戶端,好了,這下我也沒有東西要給你了,你可以終結連接了。此時伺服器不確認客戶端是否收到信息,繼續保持連接。
- 客戶機收到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
推薦閱讀: