經過故事引伸網絡協議TCP

講一個故事。


三次握手

 long time ago,通訊並不發達,兩國之間的貿易卻絡繹不絕。但碼頭始終有限,若是貿然的把貨物運過去,若是這時候有別的商家已經佔領了碼頭。這樣不得不排隊了。後來,他們訓練了一種海鳥,運送以前,先用海鳥報個信: 算法

  1. 五弟,我要發一些貨過去。
  2. 收到,老地方,不見不散。

 一開始這個方式挺好用的,直到有一年夏天,五弟找上門來了:我等了你一天,你的貨呢?我交了錢借用了一天的碼頭,都白交了。二哥:我也着急呀,你一直沒回信,我都等了兩天,我不知道咋肥四,就沒發了。應該是回信的那隻鳥,被大風颳走了。最近海上天氣很差,想必我放的那隻鳥也是歷經千辛萬苦纔去到你那。這樣吧,五弟,我改一下流程吧:緩存

  1. 五弟,我要發一些貨過去。
  2. 收到,老地方,不見不散。
  3. 五弟,好的,老地方。

五弟琢磨了一下,前面的鳥可以一來一回,二哥能看出海上沒有危險。我收到二哥的消息後也能看出海上無風雨,這時我再去借碼頭,也能節省一些時間,妙,實在妙,仍是二哥聰明,只是二哥要比我多訓練一倍的鳥。五弟哪裏的話,浪費這點資源算什麼呢。服務器

三次握手就這樣誕生了。網絡

流量控制

過了一些時日,五弟又來找二哥商量了:碼頭上的倉庫空間,人力始終有限,二哥一次派了這麼多艘船來,五弟實在忙不過來,船都堵在渡口,人家的船進不來,出不去啊。爲了此事二哥想了一宿,找來了五弟商量:五弟呀,這個確實是個頭疼的問題呀。併發

最簡單的辦法就是一開始你就告訴我你能處理多少貨,我就派一批船過去。等你處理完了通知我,我再派一批過去。可是這種方式應變能力過低了,假設港口一開始沒這麼堵,可是可能還有一些商家在海上來往,結果我這一批派過去,就致使堵塞擁擠了。這個應變能力能理太差了,要提升這個應變能力,就不能派太多的船涌進港口,只能一小批,一小批的派了。指針

這樣你每次收到貨以後,就讓回來的船告訴我你那裏剩餘多少空間,我好安排下一趟船隻。五弟撓撓頭,不明白。二哥敲了下這木魚腦殼道:假設咱們要運送720的貨,你碼頭的倉庫最多能存360的貨物,我每次派100的貨物,固然個人每艘船隻能載重是10(MTU 最大傳輸單元限制)。cdn

  • 第一趟,我送過去100,我須要派10艘過去,你讓返回的船老大告訴我你那裏還剩260的空間。
  • 第二趟,我送過去100,我須要派10艘過去,你讓返回的船老大告訴我你那裏還剩160的空間。
  • 第三趟,我送過去100,我須要派10艘過去,你讓返回的船老大告訴我你那裏還剩60的空間。
  • 第四趟,我送過去60,我須要派6艘過去,這時候倉庫已滿,你開始讓工人搬運,等你搬運好了,就通知我。
  • 第五趟,收到五弟那邊的通知,我開始送過去100,我須要派10艘過去,你讓返回的船老大告訴我你那裏還剩260的空間。
  • 第六趟,我送過去100,我須要派10艘過去,你讓返回的船老大告訴我你那裏還剩160的空間。
  • 第七趟,我送過去100,我須要派10艘過去,你讓返回的船老大告訴我你那裏還剩60的空間。
  • 第八趟,我送過去60,我須要派6艘過去,這時候貨就發完了,圓滿大吉。

藉助窗口解決了流量控制的問題。中間件

丟包重傳

沒過多久,五弟又來找二哥商量了:我收到的貨物缺斤少兩的,對不上數呀,我猜呀,海上風雲莫測,可能有些船隻失蹤了,這可咋辦呀。二哥想了想,能咋辦,重發唄。這樣,我給每個船隻編上號,到了一段時間,沒回來的船隻,我再重發那批貨物吧。至於間隔多久才決定重發,這個很是重要。
  • 設長了,重發慢了,丟了老半天才發過去,效率過低了,也讓五弟等過久了。
  • 設短了,更恐怖,可能會致使沒有丟的也重發,這樣就重發多了,更多的船堵在海上,許久不能到達返回,致使更多的超時,更多的重發。

再加上海上風雲莫測,每次來回的時間不是固定的。只能動態的估算這個值了。這樣,每批次的船隻一來一回算一個單位(RTT)。而後根據這個RTT的時間計算超時時間(RTO)當發生了重發,就會將超時時間加倍。防止太頻繁重傳致使更加擁擠。blog

重傳歧異

可是這樣的會有一個問題,假設7號船一直沒回來,這時候再派一個7號船過去,許久後,終於回來了,那麼這艘船是第一艘的仍是重發的那艘呢?忽略說能認出船老大的陳獨秀同窗(摳鼻)。隊列

  • 若是回來的船的是重發的那艘,假設是按第一艘來算,那麼間隔時間算長了。
  • 若是回來的船的是第一艘的,卻又按照重發的那艘來算,間隔時間又算短了。

這是一個苦差事,具體怎麼算,仍是請位大師來算吧。此事算了了。

慢啓動

五弟又過了找二哥了:運720的貨都跑了8趟了,那送7200的貨那還不得九九八十一趟啊。這效率不行啊,二哥道:你想到的我也想到了,一開始我並不知道海上的擁擠狀況,因此不敢派太多的船,我想了一個辦法,先發的慢一點,探測一下狀況,而後再慢慢提速。假設我一開始派n艘船。

  • 先假定cwnd = 1,表示我這個批次派 cwnd*n 艘船。
  • 每當有一艘船回來,cwnd++,線性上升。
  • 每當過一個RTT,也就是當前批次的船回來了,cwnd = cwnd *2,指數上升。

這樣,就能夠解決效率低的問題了。

擁塞避免

固然,不可能一直是增長。這樣擁堵只是時間問題。因此須要一個閾值。

  • 當 cwnd < 閾值,使用慢啓動算法
  • 當cwnd >= 閾值,使用擁塞避免算法

擁塞避免算法的思路就是下降加速度,讓它緩慢的增加。

  • 每當有一艘船回來,cwnd = 1/cwnd
  • 每當過一個RTT,cwnd++

擁塞處理

以上都是正常的狀況,當發生了重傳,說明發生了擁擠,就不能再發這麼多船了,這時候cwnd減半,從新進入慢啓動。

好了,故事就講到這裏了。

當出現了RTO超時重傳,由於ack都收不到了,因此它的處理會比較猛烈:

  • 將門限ssthresh的值設爲當前cwnd值的一半,也就是閾值。之因此減半,是爲了公平性,騰出空間給其餘新連接保證帶寬。
  • cwnd設爲1。
  • 從新進入慢啓動。

cwnd決定了發送窗口的大小,若是隻是出現了輕度的擁堵,就直接猛烈縮小窗口,進入慢啓動後,cwnd恢復的很慢,這顯然得不償失,因此須要一種主動觸發重傳的機制,就有了後來的快速重傳和快速恢復。

快速重傳

僅僅只是靠超時重傳,並不能發生了包丟失,卻要等到超時纔開始重傳,這顯然效率不夠,因此須要找到重傳的規律。雖然咱們發的包是有序的,可是IP包是無序的,因此會致使到達的包出現無序的狀況。先來看下下面一組數據。

  • 1,2,3,4        已發送,已確認到達
  • 5,6,7,8,     已發送,未確到達
  • 9,10,11 ,12    在發送緩衝區等待發送,滑動窗口已經沒有空間了。

要保證可靠性,就必需要保證順序和完整,來看看事故發生現場。

  • 5,6,7,8。ack=9 , 由於Seq=5,length = 4,ack = seq+lenght,window size 剩餘 4。不會每個都返回ack,這樣將會消耗大量的帶寬。
  • 6,5,7,8。ack=5,ack=5,ack=9,6到達的時候,發現順序不對,則會發出ack=5,期待客戶端下次發送seq=5的包,由於尚未達到三次因此客戶端不會理會這個信息,果真後面就如期而至。
  •  6,7,8,5。ack=5,ack=5,ack=5,ack=5,ack=9。重複三次了,因此後面重發了5。

從上面的狀況能夠看出不論是亂序仍是丟包,都會收到重複的ack的。在快速重傳算法中,當收到三次重複的ack,就認定它是丟包了。但實際上,三次重複ack並不能判斷出是丟包或亂序,只能說出現了問題,它只是在效率和過早重傳之間的一個權衡。

  • 若是兩次重複ack就發送可能會由於頻繁發送致使擁擠堵塞。
  • 若是太晚發送效率就跟不上。
  • 若是三次接收端都能收到重複ack,說明網絡不會太差。

收到了三次重複的ack,進入快速重傳須要作幾件事情:

  • ssthresh =cwnd/2
  • cwnd=ssthresh
  • 這時候由於cwnd等於閾值,因此從新進入擁塞避免階段

因爲快速重傳有多是由於順序的問題而誤判,或者只是輕微的擁堵,致使進入了擁塞避免階段,這時候爲了達到快速恢的目的,將會中止發送後面的數據,只發送重傳數據,爲了提升恢復效率,將會使用快速恢算法。

快速恢復

爲了保證快速重傳效率,進入快速恢復階段會有如下幾個步驟。

  • 因爲在上一個階段,cwnd和ssthresh變成了,ssthresh =cwnd/2,cwnd=ssthresh+3,之因此加3,是由於剛剛收到了3個重複的ack。
  • 當再次收到重複的ack,cwnd = cwnd+1。
  • 當收到新的ack,非重複的ack,cwnd=ssthresh,退出快速恢復階段,進入擁塞避免狀態。

總的來講就是騰出空間,馬不停蹄。

TCP 重傳機制

在上面的重傳原理介紹中,咱們還忽視了一個問題,例如客戶端在發送1,2,3,4,5,6,7包時,2,4,6,包丟了,這種狀況仍是比較常見的,這時候就會面臨一個問題,究竟是一個一個重傳,仍是將2後面的包都重發過去。

  • 停等協議。這時候接收方和發送方的窗口大小都是1,這樣每次只能發送一個,也就是一個一個重傳。缺點是效率過低。
  • 後退n幀協議。使用這個協議,爲了保證接收方有足夠的空間,2以後的數據都要丟棄,而後發送方將2後面的數據都所有發送。缺點是須要有足夠大的緩存空間。

    後退n幀協議雖然效率高,可是遇到大場面,在網絡比較差或者帶寬比較低的狀況,若是仍然使用這個協議會致使狀況更加惡劣,這種狀況停等協議雖然效率比較低,可是仍是比較適用的。


窗口的滑動

TCP提供體積可變的滑動窗口機制,支持端對端的流量控制:

  • TCP鏈接階段,雙方協商窗口的尺寸,同時接收方預留數據緩存區
  • 發送方根據協商的結果,發送符合窗口的尺寸的字節流,而後等待ack確認。
  • 發送方根據返回的確認信息,調整窗口的尺寸,調整包括,若是出現發送擁塞,發送窗口縮小原來的一半,同時將超時重傳時間間隔擴大一倍,防止發生重傳風暴。

在傳輸的過程當中,窗口是滑動的

看下圖5-15,TCP鏈接階段,雙方協商窗口的尺寸,同時接收方預留數據緩存區


看圖5-16,假設窗口的閾值是一半,因此A發送11個幀,發送後,等待確認,發送窗口位置不變。這時候發生了丟包,32,33沒有收到。雖然31已經收到了,窗口理論上能夠往右移動一個位置,可是爲了節省寬帶,不會每個幀都回復ack,而是累積幾個以後在發出,因此31不會回覆ack,窗口就卡在這了。


看圖5-17,這時候30-33的已經確認了,因此窗口能夠往右滑動三幀。37,38,40也許延遲還未收到。

看圖5-18,在重傳機制生效以前,A繼續發送了後面的數據,這時候窗口已經所有用完,A會中止發送數據,等待B的窗口可用,B處理完以後會等待A發送數據,這樣就形成了雙方在等待,爲了解決這個問題,TCP使用了Zero Window Probe技術,縮寫ZWP。在窗口尺寸變成0以後,發送端會發送ZWP包詢問接收端是否有足夠的空間能夠發送數據了,TCP使用持續計時器,若是結果仍然爲0,則重置定時器繼續等待。

丟包的緣由

  • 接收方緩存區滿了
  • 信號差,波形失真
  • 包的校檢失敗
  • 網絡擁塞

亂序的緣由

  • IP包是無序的
  • 中間件的內部調度,如路由器,路由器裏面是有處理器,有些路由器使用多個流量處理單元,致使不一樣包在不一樣的處理單元,最後到達時間不同而發生了亂序
  • 多路複用,統一連接,不一樣路徑到達

TCP包頭格式


標誌位

  • SYN 用於鏈接請求時的標誌,SYN = 1
  • ACK 用於確認成功接收數據,ACK = 1
  • FIN  用於鏈接釋放的標誌,FIN= 1
  • RST 用於重置一個異常的鏈接,接收端 告知 發送端 此鏈接有問題


  • PSH 用於通知接收端將緩存區的數據提交給上層,即便沒有滿
  • URG 用於通知接收端當前爲緊急數據,將這個數據直接提交給上層,它不通過緩存區,後面的緊急指針表示緊急數據在當前數據的偏移位置

三次握手


  • 首先整個過程Seq都是動態生成的惟一序列號,不管誰發給誰,爲了防止新鏈接和舊鏈接竄了。
  • ACK = 收到的Seq + 1
  • SYN = 1

鏈接過程的狀態

  • 客戶端SYN_SENT。客戶端發送 SYN = 1,Seq = X 將狀態設置爲 SYN_SENT
  • 服務端SYN_RCVD。半鏈接狀態,服務器收到後將狀態設置爲SYN_RCVD,並返回 SYN = 1,ACK= 1,Seq = Y,Ack = X + 1
  • 客戶端ESTABLISHED。客戶端收到後,狀態設爲ESTABLISHED,表示鏈接已創建。併發送ACK= Y + 1,Seq = Z
  • 服務端ESTABLISHED。服務端收到後,狀態設爲ESTABLISHED,表示鏈接已創建。

服務器維護了一個半鏈接的隊列,該隊列爲每一個客戶端的SYN包(SYN=X)開設一個條目,表示服務器已經收到SYN包,並向客戶端發出確認,正在等待客戶端的確認包。當服務器收到客戶端的確認包時,刪除該條目,該鏈接進入ESTABLISHED狀態。

四次揮手


  1. FIN-WAIT-1。客戶端中止發送數據,FIN=1,Seq=X(前面已經傳送過來的數據最後一個字節的序號+1),客戶端進入FIN-WAIT-1狀態。
  2. CLOSE-WAIT。服務器發出Ack = X + 1,進入CLOSE-WAIT狀態,通知應用程序,由於服務器是被動收到通知,此時服務可能數據還沒發完,還要繼續發送。
  3. FIN-WAIT-2。收到服務器的回覆,再次等待服務器的關閉通知。這時候服務器還可能發着數據給客戶端。
  4. LASK-ACK。服務器終於把事情處理完了,能夠發出FIN = 1,Seq = Z,ACK = X + 1告知服務器斷開鏈接,進入最後確認狀態。
  5. TIME-WAIT,收到服務器的關閉請求,客戶端回覆ACK = 1,Seq = X + 1,Ack = Z + 1,這時候客戶端不會立刻釋放鏈接,它會等待2MSL(報文最長存活時間),防止這個消息服務器沒有收到,而這時服務器發出重傳信息,客戶端就能夠即時響應。
  6. CLOSED,服務器收到消息後釋放鏈接,客戶端通過2MSL後也釋放鏈接。

數據是如何傳輸的

兩臺電腦之間通訊都須要把數字信號01轉化成電信號,再調製成電磁波(好比光)。電磁波自己沒法承載信息的,可是咱們能夠控制電磁波的變化(幅度AM,頻率FM,相位PM),讓這些變化能夠表明0和1。也就是說在信號線中走的是電磁波,因此在佈線的時候要注意線與線之間的串擾。

電磁波有不少頻段好比2515MHz-2675MHz、4800MHz-4900MHz,在空氣中存在不少不一樣頻段的波,因此須要進行定寬調頻,也就是說肯定帶寬,而後再進行濾波,所謂的濾波就是經過濾波算法,好比卡爾曼濾波,根據截止頻率是否靠近特徵頻率以及衰減程度來分類的,最後轉換成01信號。帶寬又叫頻寬是指在固定的的時間可傳輸的資料數量,亦即在傳輸管道中能夠傳遞數據的能力。在數字設備中,頻寬一般以 bps表示,即每秒可傳輸之位數。

截止頻率

用來講明電路頻率特性指標的特殊頻率。當保持電路輸入信號的幅度不變,改變頻率使輸出信號降至最大值的0.707倍,或某一特殊額定值時該頻率稱爲截止頻率。在高頻端和低頻端各有一個截止頻率,分別稱爲上截止頻率和下截止頻率。兩個截止頻率之間的頻率範圍稱爲通頻帶。

將信號轉化成字節,再將字節組裝成幀。再以太網鏈路上的數據包被稱爲以太幀,在802.3標準理,規定了一個以太幀的數據部分(Playload)的最大長度是1500個字節(MTU),另外,以太網幀最小長度爲64字節。

相關文章
相關標籤/搜索