TCP協(xié)議

本文作為學習筆記,文章內容來自“極客時間”專欄《趣談網絡協(xié)議》藕畔,如有侵權马僻,請告知,必即時刪除注服。

1韭邓、TCP包頭

來看 TCP 頭的格式。從這個圖上可以看出溶弟,它比 UDP 復雜得多女淑。
TCP1.jpg
  1. 源端口號和目標端口號,這一點和 UDP 是一樣的辜御。如果沒有這兩個端口號鸭你。數據就不知道應該發(fā)給哪個應用。
  2. 包的序號擒权,為了解決亂序的問題袱巨。
  3. 確認序號,發(fā)出去的包應該有確認碳抄,如果沒有收到就應該重新發(fā)送愉老,直到送達。
  4. 狀態(tài)位纳鼎,例如 SYN 是發(fā)起一個連接俺夕,ACK 是回復裳凸,RST 是重新連接贱鄙,F(xiàn)IN 是結束連接等劝贸。TCP 是面向連接的,因而雙方要維護連接的狀態(tài)逗宁,這些帶狀態(tài)位的包的發(fā)送映九,會引起雙方的狀態(tài)變更。
  5. 窗口大小瞎颗,TCP 要做流量控制件甥,通信雙方各聲明一個窗口,標識自己當前能夠的處理能力哼拔,別發(fā)送的太快引有,也別發(fā)的太慢。所謂的流量控制就是讓發(fā)送方的發(fā)送速率不要太快倦逐,讓接收方來得及接受譬正。針對的是建立TCP連接的對端。

除了做流量控制以外檬姥,TCP 還會做擁塞控制曾我,對于真正的通路堵車不堵車,它無能為力健民,唯一能做的就是控制自己抒巢,也即控制發(fā)送的速度。擁塞控制針對的是網絡秉犹。

2蛉谜、三次握手

TCP 的連接建立,我們常常稱為三次握手崇堵。我們也常稱為“請求 -> 應答 -> 應答之應答”的三個回合悦陋。

為什么要三次,而不是兩次筑辨?按說兩個人打招呼俺驶,一來一回就可以了啊棍辕?為了可靠暮现,為什么不是四次?

假設兩次握手的情況楚昭,A要發(fā)起請求栖袋,和B建立連接,請求到達B之后抚太,B返回應答包塘幅,雙方建立連接昔案。如果A發(fā)送請求包之后掛了泣棋,B收到請求包兜看,返回應答包,建立連接狂塘,這個時候A已經掛了匾乓,自然不會再發(fā)送數據給B捞稿,因此B這個連接只能一直保持著。因而兩次握手肯定不行拼缝。

B 發(fā)送的應答到達 A娱局,A 就認為連接已經建立了,因為對于 A 來講咧七,他的消息有去有回衰齐。A 會給 B 發(fā)送應答之應答,而 B 也在等這個消息继阻,才能確認連接的建立耻涛,只有等到了這個消息,對于 B 來講穴翩,才算它的消息有去有回犬第。當然 A 發(fā)給 B 的應答之應答也會丟,也會繞路芒帕,甚至 B 掛了歉嗓。按理來說,還應該有個應答之應答之應答背蟆,這樣下去就沒底了鉴分。所以四次握手是可以的,四十次都可以带膀,關鍵四百次也不能保證就真的可靠了志珍。只要雙方的消息都有去有回,就基本可以了垛叨。

我們在程序設計的時候伦糯,可以要求開啟 keepalive 機制,即使沒有真實的數據包嗽元,也有探活包敛纲。另外,你作為服務端 B 的程序設計者剂癌,對于 A 這種長時間不發(fā)包的客戶端淤翔,可以主動關閉,從而空出資源來給其他客戶端使用佩谷。

三次握手除了雙方建立連接外旁壮,主要還是為了溝通一件事情监嗜,就是 TCP 包的序號的問題。

A 要告訴 B抡谐,我這面發(fā)起的包的序號起始是從哪個號開始的裁奇,B 同樣也要告訴 A,B 發(fā)起的包的序號起始是從哪個號開始的童叠。

每個連接都要有不同的序號框喳。這個序號的起始序號是隨著時間變化的课幕,可以看成一個 32 位的計數器厦坛,每 4 微秒加一,如果計算一下乍惊,如果到重復杜秸,需要 4 個多小時,那個繞路的包早就死翹翹了润绎,因為我們都知道 IP 包頭里面有個 TTL撬碟,也即生存時間。在連接建立的過程中莉撇,雙方的狀態(tài)變化時序圖就像這樣呢蛤。


TCP2.jpg

一開始,客戶端和服務端都處于 CLOSED 狀態(tài)棍郎。先是服務端主動監(jiān)聽某個端口其障,處于 LISTEN 狀態(tài)。然后客戶端主動發(fā)起連接 SYN涂佃,之后處于 SYN-SENT 狀態(tài)励翼。服務端收到發(fā)起的連接,返回 SYN辜荠,并且 ACK 客戶端的 SYN汽抚,之后處于 SYN-RCVD 狀態(tài)〔。客戶端收到服務端發(fā)送的 SYN 和 ACK 之后造烁,發(fā)送 ACK 的 ACK,之后處于 ESTABLISHED 狀態(tài)午笛,因為它一發(fā)一收成功了惭蟋。服務端收到 ACK 的 ACK 之后,處于 ESTABLISHED 狀態(tài)季研,因為它也一發(fā)一收了敞葛。

3、四次揮手

斷開連接的時候的狀態(tài)時序圖与涡。


TCP3.jpg

斷開的時候惹谐,我們可以看到持偏,當 A 說“不玩了”,就進入 FIN_WAIT_1 的狀態(tài)氨肌,B 收到“A 不玩”的消息后鸿秆,發(fā)送知道了,就進入 CLOSE_WAIT 的狀態(tài)怎囚。A 收到“B 說知道了”卿叽,就進入 FIN_WAIT_2 的狀態(tài),A 發(fā)送“知道 B 也不玩了”的 ACK 后恳守,從 FIN_WAIT_2 狀態(tài)結束考婴。

按說 A 可以跑路了,但是最后的這個 ACK 萬一 B 收不到呢催烘?則 B 會重新發(fā)一個“B 不玩了”沥阱,這個時候 A 已經跑路了的話,B 就再也收不到 ACK 了伊群,因而 TCP 協(xié)議要求 A 最后等待一段時間 TIME_WAIT考杉,這個時間要足夠長,長到如果 B 沒收到 ACK 的話舰始,“B 說不玩了”會重發(fā)的崇棠,A 會重新發(fā)一個 ACK 并且足夠時間到達 B。

等待的時間設為 2MSL丸卷,MSL 是 Maximum Segment Lifetime枕稀,報文最大生存時間,它是任何報文在網絡上存在的最長時間及老,超過這個時間報文將被丟棄抽莱。

4、TCP的滑動窗口

為了記錄所有發(fā)送的包和接收的包骄恶,發(fā)送端的緩存里是按照包的 ID 一個個排列食铐,根據處理的情況分成四個部分。

  1. 第一部分:發(fā)送了并且已經確認的僧鲁。
  2. 第二部分:發(fā)送了并且尚未確認的虐呻。
  3. 第三部分:沒有發(fā)送,但是已經等待發(fā)送的寞秃。
  4. 第四部分:沒有發(fā)送斟叼,并且暫時還不會發(fā)送的。

在 TCP 里春寿,接收端會給發(fā)送端報一個窗口的大小朗涩,叫 Advertised window。這個窗口的大小應該等于上面的第二部分加上第三部分绑改,就是已經交代了沒做完的加上馬上要交代的谢床。超過這個窗口的兄一,接收端做不過來,就不能發(fā)送了识腿。于是出革,發(fā)送端需要保持下面的數據結構。

TCP4.jpg

  • LastByteAcked:第一部分和第二部分的分界線
  • LastByteSent:第二部分和第三部分的分界線
  • LastByteAcked + AdvertisedWindow:第三部分和第四部分的分界線

對于接收端來講渡讼,它的緩存里記錄的內容要簡單一些骂束。

  1. 第一部分:接受并且確認過的。
  2. 第二部分:還沒接收成箫,但是馬上就能接收的展箱。
  3. 第三部分:還沒接收,也沒法接收的伟众。
TCP5.jpg
  • LastByteRead 之后是已經接收了析藕,但是還沒被應用層讀取的召廷;
  • NextByteExpected 是第一部分和第二部分的分界線凳厢。
  • MaxRcvBuffer:最大緩存的量;

5竞慢、順序問題與丟包問題

還是剛才的圖先紫,在發(fā)送端來看,1筹煮、2遮精、3 已經發(fā)送并確認;4败潦、5本冲、6、7劫扒、8檬洞、9 都是發(fā)送了還沒確認;10沟饥、11添怔、12 是還沒發(fā)出的;13贤旷、14广料、15 是接收方沒有空間,不準備發(fā)的幼驶。
在接收端來看艾杏,1、2盅藻、3购桑、4汹族、5 是已經完成 ACK,但是沒讀取的其兴;6顶瞒、7 是等待接收的;8元旬、9 是已經接收榴徐,但是沒有 ACK 的。
發(fā)送端和接收端當前的狀態(tài)如下:

  • 1匀归、2坑资、3 沒有問題,雙方達成了一致穆端。
  • 4袱贮、5 接收方說 ACK 了,但是發(fā)送方還沒收到体啰,有可能丟了攒巍,有可能在路上。
  • 6荒勇、7柒莉、8、9 肯定都發(fā)了沽翔,但是 8兢孝、9 已經到了,但是 6仅偎、7 沒到跨蟹,出現(xiàn)了亂序,緩存著但是沒辦法 ACK橘沥。

根據這個例子,我們可以知道威恼,順序問題和丟包問題都有可能發(fā)生品姓,所以我們先來看確認與重發(fā)的機制箫措。一種方法就是超時重試,也即對每一個發(fā)送了斤蔓,但是沒有 ACK 的包植酥,都有設一個定時器,超過了一定的時間,就重新嘗試友驮。每當遇到一次超時重傳的時候漂羊,都會將下一次超時時間間隔設為先前值的兩倍。兩次超時卸留,就說明網絡環(huán)境差走越,不宜頻繁反復發(fā)送。

有一個可以快速重傳的機制耻瑟,當接收方收到一個序號大于下一個所期望的報文段時旨指,就會檢測到數據流中的一個間隔,于是它就會發(fā)送冗余的 ACK喳整,仍然 ACK 的是期望接收的報文段谆构。還有一種方式稱為 Selective Acknowledgment (SACK)。(TODO:這兩種我沒看太明白框都,后面再補吧)

6搬素、流量控制問題

在對于包的確認中,同時會攜帶一個窗口的大小魏保。
對于發(fā)送端熬尺,我們先假設窗口不變的情況,窗口始終為 9囱淋。4 的確認來的時候猪杭,會右移一個,這個時候第 13 個包也可以發(fā)送了妥衣。


TCP6.jpg

我們假設一個極端情況,接收端的應用一直不讀取緩存中的數據戒傻,當數據包 6 確認后税手,窗口大小就不能再是 9 了,就要縮小一個變?yōu)?8需纳。


TCP7.jpg

這個新的窗口 8 通過 6 的確認消息到達發(fā)送端的時候芦倒,你會發(fā)現(xiàn)窗口沒有平行右移,而是僅僅左面的邊右移了不翩,窗口的大小從 9 改成了 8兵扬。
TCP8.jpg

如果接收端還是一直不處理數據,則隨著確認的包越來越多口蝠,窗口越來越小器钟,直到為 0。當這個窗口通過包 14 的確認到達發(fā)送端的時候妙蔗,發(fā)送端的窗口也調整為 0傲霸,停止發(fā)送。這就是我們常說的流量控制。

7昙啄、擁塞控制問題

擁塞控制的問題穆役,也是通過窗口的大小來控制的,前面的滑動窗口 rwnd是怕發(fā)送方把接收方緩存塞滿梳凛,而擁塞窗口 cwnd耿币,是怕把網絡塞滿。

這里有一個公式 LastByteSent - LastByteAcked <= min {cwnd, rwnd} 韧拒,是擁塞窗口和滑動窗口共同控制發(fā)送的速度掰读。就是發(fā)送方的第二部分(已發(fā)送但未確認的)<= 滑動窗口和擁塞窗口的最小值。

TCP 的擁塞控制主要來避免兩種現(xiàn)象叭莫,包丟失和超時重傳蹈集。一旦出現(xiàn)了這些現(xiàn)象就說明,發(fā)送速度太快了雇初,要慢一點拢肆。但是一開始我怎么知道速度多快呢,我怎么知道應該把窗口調整到多大呢靖诗?如果我們通過漏斗往瓶子里灌水郭怪,我們就知道,不能一桶水一下子倒進去刊橘,肯定會濺出來鄙才,要一開始慢慢的倒,然后發(fā)現(xiàn)總能夠倒進去促绵,就可以越倒越快攒庵。這叫作慢啟動。

一條 TCP 連接開始败晴,cwnd 設置為一個報文段浓冒,一次只能發(fā)送一個;當收到這一個確認的時候尖坤,cwnd 加一稳懒,于是一次能夠發(fā)送兩個;當這兩個的確認到來的時候慢味,每個確認 cwnd 加一场梆,兩個確認 cwnd 加二,于是一次能夠發(fā)送四個纯路;當這四個的確認到來的時候或油,每個確認 cwnd 加一,四個確認 cwnd 加四感昼,于是一次能夠發(fā)送八個装哆。可以看出這是指數性的增長

漲到什么時候是個頭呢蜕琴?有一個值 ssthresh 為 65535 個字節(jié)萍桌,當超過這個值的時候,就要小心一點了凌简,不能倒這么快了上炎,可能快滿了,再慢下來雏搂。每收到一個確認后藕施,cwnd 增加 1/cwnd,我們接著上面的過程來凸郑,一次發(fā)送八個裳食,當八個確認到來的時候,每個確認增加 1/8芙沥,八個確認一共 cwnd 增加 1诲祸,于是一次能夠發(fā)送九個,變成了線性增長而昨。

后來有了 TCP BBR 擁塞算法救氯。它企圖找到一個平衡點,就是通過不斷地加快發(fā)送速度歌憨,將管道填滿着憨,但是不要填滿中間設備的緩存,因為這樣時延會增加务嫡,在這個平衡點可以很好的達到高帶寬和低時延的平衡甲抖。

?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市植袍,隨后出現(xiàn)的幾起案子惧眠,更是在濱河造成了極大的恐慌,老刑警劉巖于个,帶你破解...
    沈念sama閱讀 217,826評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異暮顺,居然都是意外死亡厅篓,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,968評論 3 395
  • 文/潘曉璐 我一進店門捶码,熙熙樓的掌柜王于貴愁眉苦臉地迎上來羽氮,“玉大人,你說我怎么就攤上這事惫恼〉笛海” “怎么了?”我有些...
    開封第一講書人閱讀 164,234評論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長令宿。 經常有香客問我叼耙,道長,這世上最難降的妖魔是什么粒没? 我笑而不...
    開封第一講書人閱讀 58,562評論 1 293
  • 正文 為了忘掉前任筛婉,我火速辦了婚禮,結果婚禮上癞松,老公的妹妹穿的比我還像新娘爽撒。我一直安慰自己,他們只是感情好响蓉,可當我...
    茶點故事閱讀 67,611評論 6 392
  • 文/花漫 我一把揭開白布硕勿。 她就那樣靜靜地躺著,像睡著了一般枫甲。 火紅的嫁衣襯著肌膚如雪源武。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,482評論 1 302
  • 那天言秸,我揣著相機與錄音软能,去河邊找鬼。 笑死举畸,一個胖子當著我的面吹牛查排,可吹牛的內容都是我干的。 我是一名探鬼主播抄沮,決...
    沈念sama閱讀 40,271評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼跋核,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了叛买?” 一聲冷哼從身側響起砂代,我...
    開封第一講書人閱讀 39,166評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎率挣,沒想到半個月后刻伊,有當地人在樹林里發(fā)現(xiàn)了一具尸體,經...
    沈念sama閱讀 45,608評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡椒功,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,814評論 3 336
  • 正文 我和宋清朗相戀三年捶箱,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片动漾。...
    茶點故事閱讀 39,926評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡丁屎,死狀恐怖,靈堂內的尸體忽然破棺而出旱眯,到底是詐尸還是另有隱情晨川,我是刑警寧澤证九,帶...
    沈念sama閱讀 35,644評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站共虑,受9級特大地震影響愧怜,放射性物質發(fā)生泄漏。R本人自食惡果不足惜看蚜,卻給世界環(huán)境...
    茶點故事閱讀 41,249評論 3 329
  • 文/蒙蒙 一叫搁、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧供炎,春花似錦渴逻、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,866評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至竭钝,卻和暖如春梨撞,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背香罐。 一陣腳步聲響...
    開封第一講書人閱讀 32,991評論 1 269
  • 我被黑心中介騙來泰國打工卧波, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人庇茫。 一個月前我還...
    沈念sama閱讀 48,063評論 3 370
  • 正文 我出身青樓港粱,卻偏偏與公主長得像,于是被迫代替她去往敵國和親旦签。 傳聞我的和親對象是個殘疾皇子查坪,可洞房花燭夜當晚...
    茶點故事閱讀 44,871評論 2 354

推薦閱讀更多精彩內容

  • TCP如何實現(xiàn)一個靠譜的協(xié)議 為了保證順序性,每個包都有一個ID宁炫。在建立連接的時候偿曙,商定起始的ID。然后按照ID一...
    空擋閱讀 1,813評論 0 1
  • TCP TCP最核心的一點就是可靠的傳輸協(xié)議羔巢,那么TCP是靠什么來保證可靠的傳輸服務呢望忆? 三次握手 就如同打電話一...
    芒果菠蘿蛋炒飯閱讀 409評論 0 1
  • TCP是面向連接的,可靠的竿秆,基于字節(jié)流的傳輸層通信協(xié)議炭臭。 面向連接:一對一的連接,不像UDP協(xié)議可以一個主機同時向...
    365_9163閱讀 654評論 0 0
  • 昨天下班在地鐵上看到一篇關于TCP總結的博文袍辞,覺得非常好,這里借鑒過來常摧,由于原文里有一些關于TCP協(xié)議部分晦澀難懂...
    不知名的程序員閱讀 12,613評論 3 12
  • 序列號seq占4個字節(jié)搅吁,用來標記數據段的順序威创,TCP把連接中發(fā)送的所有數據字節(jié)都編上一個序號,第一個字節(jié)的編號由本...
    半數的年閱讀 401評論 0 0