忽然發現上一篇文章貼圖有問題,關鍵我怎麼調也調很差,爲了表達歉意,我再貼一篇gitbook上的吧,雖然違背了我本身的隔一篇在這裏發一次的潛規則~其他完整版能夠去gitbook(https://rogerzhu.gitbooks.io/-tcp-udp-ip/content/)看到。git
若是對和程序員有關的計算機網絡知識,和對計算機網絡方面的編程有興趣,雖說如今這種「看不見」的東西真正能在實用中遇到的機會很少,可是我始終以爲不管計算機的語言,熱點方向怎麼變化,做爲一個程序員,不少基本的知識都應該有所瞭解。而當時在網上搜索資料的時候,這方面的資料真的是少的可憐,因此,我有幸前兩年接觸了這方面的知識,我以爲我應該把我知道的記錄下來,雖然寫的不必定很好,可是但願能給須要幫助的人多個參考。個人計劃是用半年時間來寫完這一系列文章,這個標題也是我對太多速成文章的一種態度,好了,廢話再也不多扯了,下面是其中的一節內容,更多內容能夠去gitbook上找到。程序員
TCP是一個可靠的傳輸協議,這個可靠是靠着衆多富有智慧的設計保證的,而瞭解這其中的奧祕不只僅是認識TCP的核心,並且對生活中協議的實現也有不少借鑑價值,首先就從最基礎的停等協議開始吧。面試
其實停等的概念在前面介紹TFTP的時候就介紹過,停等協議其實更加正統的名字應該是屬於中止等待ARQ(Automatic Repeat-reQuest)的一部分,翻譯成中文還真的一時想不到用什麼比較貼切。爲了更加可以符合大多數人的通用名稱,在後面的文字中,我就用ARQ來代指停等這種過程了。就像在前面看到的,中止等待ARQ有兩個重要的方面,一個是中止和等待的過程,另一個是編號識別,首先仍是從最簡單的正常模式開始看看什麼叫作中止等待ARQ。編程
這副圖中水平箭頭的兩端標識兩個通訊端,上面的叫作S端,下面的叫作R端吧。還能夠看到在S端和R端都有若干6個格子組成的長方形,這些長方形分爲兩個部分,在S端黃色的表示的是其接收緩衝區,白色的那一列是發送緩衝區。而下面的R端黃色的發送緩衝區,白色的是接收緩衝區,和S端相反。而每一個格子表示一個包,也就是說S端有三個包要發送。網絡
首先S端發送了1號包,在發送的過程當中S端會拷貝一份這個1號包,用處在下面就會介紹,在S端的第二個長方形中用虛線表示了拷貝。而R端在接收到了這個包以後,會把1號包放到本身的接收緩衝區中,而後產生一個對1號包的ACK包,用黃色格子而且標號1表示。這個回覆包會發送回S端做爲對1號數據包的確認。至此,一次通訊過程就完成了,後面的過程纔會進行。S端等着R端的確認才進行下一次,這樣保證了每一次的通訊對於雙方都是可靠的。tcp
可是,因爲網路自己並非可靠的,發送出去的1號包可能會由於網絡網路自己的問題就消失了,這個消失並不會通知到S端,在如此一個複雜的網絡裏要設計出這樣一個機制不只費時並且太佔用資源。因此在TCP中,超時重發是一個最簡單而又有效的辦法,雖然會浪費一些時間,可是相比於前面所述的機制成本要小太多。spa
除了包發着發着就消失了,另一種可能出現的狀況是包在圖中迷路了,花了好多時間纔到達對端,這個時間比發送端的重傳計時器都長,這個叫作延遲,這個和網遊裏網絡延遲不是一個概念。下面就要詳細的看看這些異常狀況,只有理解了這些異常狀況才能繼續進一步理解TCP中的ARQ。計算機網絡
首先第一種狀況是發送端的包在網絡中丟失了,一樣,我仍是畫了圖。翻譯
假設在接下來的發送過程當中,2號包在發送的過程當中丟失了,這個時候TCP實現中的拷貝包就有幫助了,在等待了一段時間以後,也就是重傳定時器到期了以後,再次從新發送這個2號包。注意,這個重傳計時器的時間確定要比一個包在信道中往返時間(RTT)要長一些。爲何?由於若是不是這樣,發送端如何確認是丟包了仍是隻是等待的人尚未來?這個知識點,在面試的時候問人能答上來的不會超過一半。因此在圖中,這個空隙我故意畫個大的,在這裏假設第二次傳輸就成功了,在通過第二次重傳以後,就回到上面一種狀況。設計
下面介紹第二種可能發生的錯誤的狀況,假設發送端的包正確的到達了接收端,可是接收端傳回來的確認卻丟失了。
若是是R端的回覆丟失,其實站在S端這邊,他是不可能知道究竟是3號包丟失了仍是回送的3號包的應答包丟失了,在S端,這兩種行爲沒有任何區別。因此在重傳計數器到期以後,S端會重傳其保存的3號副本。而在這個包再次到達對端以後,R端的接收緩衝區中已經有了3號包了,這時又一次到達了3號包,這個時候R端就會直接丟棄掉這個重複到達的3號包,由於R端已經擁有了。此時其實R端就能知道本身回覆丟失了,由於受到了重複包,因此他再一次的發送這個對3號包的應答。
上面所說的都是包在傳輸過程當中丟失的狀況,除了這種狀況,還會有一種包走着走着就迷路了,可是通過了一段時間以後,它又在各類路由協議的指導下找到了正確的道路,到達了對端。而恰恰就在這個迷路的時間裏,S端由於半天沒有收到對端的回覆覺得本身的包丟失了,因此又重發了一遍的包。這個狀況用圖來表示更加清晰。
在這個圖中R端的3號應答包迷失了,在重傳定時器到期以後S端又重傳了3號包,這個包讓R端知道本身的3號應答包由於某種緣由沒有到達對端。此時,R端再次發送3號應答包,而且成功到達了對端。可過了一段時間以後,那個迷路的3號應答包又一次的到達了S端,而這個時候S端的接收緩衝區中已經有了3號應答包,S端會簡單的丟棄掉這個重複的3號應答包。
上面說的等待中止ARQ確實能夠保證數據可靠的在一個不可靠的信道上傳輸,可是有一個很現實的問題,對於這種每次發送一個包而後再確認一個包效率實在是過低,上面所畫的只是一次通訊的過程,若是咱們按照上面的方式把6次成功的過程畫在一個圖上就是下面 這張圖的上面的樣子。
而下面這個圖就是如今要介紹的連續ARQ協議了,連續ARQ相對於停等ARQ,其信道的利用率大大提升,一樣發送6個包,前面的停等ARQ比連續ARQ要花了更多的時間。說了這麼多,那麼什麼叫作連續ARQ呢?連續ARQ就是不要那麼快的發送確認,等接收端接收到幾個包以後再發送確認,這樣作的好處,第一明顯的是減少了通訊的流量,其次也省去了不少時間,這一點, 從圖中的長短也能看出來其變化。
在實際的實現過程當中,TCP會維護一個被稱之爲「窗口」的東西和累積確認的機制來實現這個連續ARQ。用數學的概念來描述,能夠理解爲是一個將要發送全部數據的一個子集,這個子集中包括的是能夠發送的數據包範圍。抽象成一個圖的話就以下面同樣:
好比說要發送的數據包一共有8個,這些包都存在於TCP發送端的發送緩衝區中,而圖中綠色的就是目前能夠一次發送最大的數據包的範圍,稱之爲「滑動窗口」,具體的來講就是在窗口內的數據包能夠一次性發出去而不須要等待對端的確認,而不是像停等模式那樣非要一包一包的發而後等待對方的確認。
而對端會根據自身的狀況選擇能夠確認的數據包,以上圖爲例,對端在收到2號數據包以後發送了對編號爲2的ACK包,在TCP的設計中,ACK包的中的確認序號標識該序號以前的包都已經收到,這種機制叫作「累積確認」。發送端在接收到2號ACK包以後,就能夠更改最大能夠一次性發送的數據包範圍,由於這個時候發送端已經知道有1,2號包已經妥善的投遞到對端。這種操做就像咱們推窗戶同樣,「窗戶」向後面「滑動」,是否是很形象?因此有時候計算機工做者也很藝術很生活的。
正如前面所述的,任何異常狀況都是TCP這樣一個聲稱「可靠」的協議須要考慮和解決的。在上面的「窗口」機制中,「窗口"中的全部數據包能夠一次性發出而不須要等待任何確認。那麼假設這麼一種狀況,若是1-5的包一次性發出去了,可是2,3號包丟失了,最後1,4,5號包到了,對端會怎麼樣?按照前面的「累積確認"機制,對端不可能發送編號爲5的ACK包,由於這樣會致使發送端認爲5號包之前的都妥善的接收了。實際上,對端只能發送對1號包的ACK包,由於這樣才能不打破「累積確認"的規則。那麼發送端的窗口只能向後移動一個包,這種機制叫作"Go-back-N",俗成"滾回未肯定的時候",在這個狀況下,發送端只能 go back 到2號包,從新發送2-6號包。
滑動窗口的概念在TCP中十分的經典,在下一篇中會更加詳細的講述這個著名的"滑動窗口"。