計算機網路學習整理:傳輸層tcp協議

上章計算機網絡的學習整理中整理了Http協議的內容,今天的文章中整理一下tcp協議。html

文章中部分圖片來自於網絡,侵刪算法

首先介紹一下tcp協議, tcp一種可靠的,面向鏈接的服務,它爲端與端之間的進程通訊提供了可靠的數據傳輸功能,經過流量控制,序號,確認和定時器等功能,tcp可以講數據按序正確的從原進程傳遞到目標進程中。緩存

多路複用以及多路分解

多路複用以及多路分解是由網絡層提供的主機到主機交付服務延伸到爲運行在主機上的應用程序提供進程到進程的交付服務。一個進程(做爲網絡應用的一部分)有一個或多個套接字(socket),它至關於從網絡向進程傳遞數據和從進程向網絡傳遞數據的門戶。將運輸層報文段中的數據交付到正確的套接字的工做稱爲多路分解(demultiplexing)。而在源主機中從不一樣套接字中收集數據塊,併爲每一個數據塊封裝上首部信息從而生成報文段,而後將報文段傳遞到網絡層,全部這些工做稱爲多路複用(multiplexing)。服務器

從上面概念來看,多路複用以及多路分解就是一個對稱關係的概念。接下來看下多路複用以及多路分解在傳輸層封裝的報文段中的表現:網絡

  • 端口號爲16bit範圍數字,大小在[0-65535],其中0-1023爲周知端口號,不容許用戶使用,如Http(80),FTP(21)等等

可靠數據傳輸原理

咱們在開發時候都知道TCP是一個可靠的傳輸協議,那麼爲何是可靠的呢?這個可能不少人並不瞭解。首先咱們來試想一想看可能會發生的問題:併發

  • 問題一:分組數據出錯了該怎麼處理呢?
  • 問題二:如何去保證按序傳遞數據呢?
  • 問題三:分組數據丟失了怎麼辦?

這些問題在數據傳輸中確定時會遇到的,那麼該怎麼解決這些問題呢?socket

自動重傳請求協議(ARQ)

首先看看第一個問題,發生情境多是底層物理部件時候發生問題,致使了分組數據中有概率使一個比特數據從0變成了1。如何處理呢?在《計算機網絡-自頂向下》中舉了一個情景,我以爲挺好:在打電話中,咱們在正常狀況就正常對話就能夠了,若是對方忽然說話聲音聽不清了,那麼咱們就會讓他重複一下上次說的話。那麼在第一種問題情境中,咱們也可使用這種方式來處理,這種基於重傳的可靠數據傳輸協議叫自動重傳請求協議(ARQ)tcp

在ARQ中包含三種方式處理比特差錯的狀況:性能

  • 差錯檢測:提供一種機制來使接收方檢測到比特發生差錯,如(奇偶校驗)。
  • 接收方反饋:對發送方發來的數據進行反饋,接收方返回結果給發送方時候帶上"確定確認"(ACK)和"否認確認"(NAK)。
  • 重傳:接收到由差錯分組的時候,發送方從新發送分組數據。

這三種方式是按序發生的,當發送方發出數據的時候,接收方在接收到的同事進行差錯檢測,若是出現問題,那麼接收方在答覆的時候,在數據中帶上NAK,反之帶上ACK。發送方在拿到響應數據的時候,若是收到NAK時候,則進行重傳。這裏還得考慮一個問題,萬一接收方的反饋也被物理部件影響返回徹底錯誤的結果了怎麼辦呢?既然發生了,那麼咱們重發一次分組不就行了麼,不是ACK的答覆,都按照NAK來處理,其實不就處理好了麼?經過這種方式是能解決問題,可是可能會形成一個問題:因爲發送方不清楚接收方是否收到了數據,因此發兩次給接收方可能形成冗餘分組的問題。學習

如何卻解決冗餘分組的問題呢,TCP中會對每個分組帶上序號,這樣接收方能夠去判斷是重複數據仍是初始數據,若是接收方最近收到了相同序號的分組,那麼就是重複數據了。而且,經過序號的方式,接收方在收到數據的時候可不只能夠處理重複數據的問題,也能處理數據順序的問題,接收方能夠按照序號對失序的分組集進行重組傳遞給接收方應用程序,那麼問題二情境也就天然而然解決了。

最後看下問題三,分組數據丟失了怎麼辦?可能發送方的分組數據丟了沒到達接收方手裏,也可能接收方返回的響應數據丟了,那麼這個時候該怎麼處理呢?這個問題其實很簡單,咱們針對每一個分組數據設置一個定時器不就完了麼。在定時器規定時間內沒有獲得響應數據,發送方就進行重傳的操做就行了。

經過ARQ協議就可以保證數據的可靠傳輸,可是效率也是須要去重視的,如何在保證數據可靠傳輸的狀況下進行高效的做業呢?

首先考慮最簡單的狀況,就是串行進行上面的一系列操做,一個分組操做完後才進行下一個分組的傳輸。這樣的方式稱之爲停等協議。這種協議對於網絡利用率實在太差了,咱們能夠類比一下若是咱們在一個線程中進行一系列串行I/O的操做,這個咱們是不能接受的。

那麼改爲類比並發的方式處理確定是更爲穩當的,咱們容許發送多個分組無需等待確認,這種技術稱之爲流水線,經過該技術對可靠傳輸協議會帶來影響以下:

  1. 增長序號範圍,天然你傳遞的分組多了,那麼相對應的序號數量確定就上去了。
  2. 發送方和接收方須要由緩存多個分組。
  3. 所須要的序號範圍以及對緩衝的要求取決於數據傳輸協議如何處理丟失,損壞以及延時過大的分組。

上面的影響TCP的開發人員提出了兩種方式去解決:回退N步以及選擇重傳

回退N步協議(滑動窗口協議)

回退N步協議(GBN)也稱之爲滑動窗口協議,其做用是容許發送方發送多個分組並且無需等待確認,可是受限於流水線中未確認的分組的最大數不能超過N。下面的圖中顯示了發送方的序號範圍:

能夠看到在窗口長度範圍內有已發送但未確認的數據,以及可用可是未發送的數據,在後面的數據(紫紅色)只能等待窗口中的數據發送被確認後纔有機會進入窗口中,至關於窗口主動進行了滑動,這也就是GBN稱爲滑動窗口協議的緣由。

GBN的運行過程以下描述:

  • 首先在發送方進行發送數據的時候,首先會檢查滑動窗口中是否有數據,沒有的話則加入滑動窗口,而且當即發送;若是窗口滿了,則在緩衝區中進行等待調用。
  • 在接收方接收到數據的時候會驗證該數據性的正確性,須要注意的是GBN協議要求數據是按序傳遞的,若是數據失序了,接收方會丟棄全部失序分組,也就是說,GBN能夠保證序號爲n的分組以前全部數據都是正確排序接收到的,這種方式稱之爲累計確認。當數據正確,則接收方返回一個ACK給發送方。
  • 若是發送方檢測到了超時事件或者錯誤事件,那麼發送方會重傳全部已發送的還未被確認過的分組數據,這也是爲何被稱之爲回退N步協議的緣由。

GBN好處在於容許發送方發送多個分組並且無需等待確認,可是也存在着很是明顯的性能問題,單個分組一旦出了錯就會自動重傳全部已發送未確認的數據,所以又提出了選擇重傳協議。

選擇重傳協議

選擇重傳協議經過讓發送發僅僅重傳接收方出錯的分組,避免沒必要要的重傳操做。這種個別的,按需的重傳要求接收方逐個確認正確接收的分組,再次用窗口長度N來限制流水線中未完成,違背確認的分組數。接收方會接收失序的分組,直到全部丟失的分組被接收到爲止,而後按序的交付於上層程序。

選擇確認機制

選擇確認機制能夠認爲是選擇重傳以及回退N步協議的綜合體,即接收方有選擇性的確認失序的報文段,而不是累計確認最後一個正確接收的有序報文段,只重傳未被接收方確認過的報文段。更加詳細的內容能夠看這篇文章,寫的很是淺顯易懂。

這裏總結一下可靠數據傳輸原理思路圖:


TCP協議

首先整理一下該節中會遇到的縮寫:

  • MSS:最大報文段長度
  • rwnd:接收窗口
  • cwnd:擁塞窗口
  • Seq:序號
  • ACK:確認號
  • ssthresh:慢啓動閾值
  • SYN:同步序列編號(Synchronize Sequence Numbers),是TCP/IP創建鏈接時使用的握手信號。

TCP協議是基於可靠數據傳輸原理,這也是爲何上面整理了:靠數據傳輸原理的相關內容。首先看下TCP報文段結構吧:

TCP的首部爲20字節,主要的字段說明以下:

  • 32比特的序號字段(Seq)以及32比特的確認號(ACK)字段,用於發送方和接收方實現可靠數據傳輸服務。
  • 16比特接收窗口(rwind)字段,即圖中的窗口大小,用於流量控制,標識接收方願意接受的字節數量。
  • 6比特的標誌字段,其中ACK確認數據的有效性,RST,SYN,FIN標識連接的簡歷和拆除(三次握手中能夠見到)。

首先介紹一下序號字段,序號的概念創建在傳送的字節流之上,一個報文段的序號爲報文段首字節流的編號,假設一段字節流爲1000字節,每一個報文段大小爲200字節,那麼第一個報文段序號爲0,第二個爲200,第三個爲400,以此類推。

確認號的概念則是發送方但願從接送方收到的下一節數據的序號,好比發送方已經從接收方收到了0-200字節的數據,此時發送方再發送一個報文段給接收方,而且帶上確認號201,代表但願收到201以及以後的全部字節。

接下來畫個流程圖來加深理解一下序號和確認號的概念吧,假設客戶端和服務端的字節流的起始序號分別爲20和40,而且報文段的字節大小都是1字節:

  • 首先客戶端發送序號20,因爲尚未數據從服務端接收,因此確認號爲40,表示當前客戶端的字節流序號爲20,而且但願從服務端接收到確認號40以及之後的數據。
  • 服務端接收到客戶端傳來的報文段,解析得到結果知道了客戶端的需求,因此服務端發送的序號爲40,而且發送確認號21表示21之前的數據已經收到了,但願接收21以及之後的數據。
  • 客戶端接收到了服務端傳來的消息,知道了服務端的需求,發送了序號爲21,以及確認號爲41的報文段給服務端。

三次握手和四次揮手

TCP協議經過三次握手和四次揮手來保證鏈接的創建與拆除操做。首先看下三次握手:

  • 首先客戶端的TCP向服務器發送一個特殊的TCP報文段,該報文段是不包含應用層數據的,在這個報文段首部中的SYN標誌位會被設置爲1,在上面報文段結構中能夠看到對應的結構位置。另外,客戶端會隨機選擇一個初始序號x放在報文段中的序號字段中。
  • 服務器收到客戶端發過來的報文段,解析獲取SYN字段值,而且爲該TCP鏈接分配緩存和變量,而且向客戶端發送容許鏈接的報文段。該報文段中也不包含應用層數據,主要包含三個信息:SYN字段設置爲1,ACK設置爲x+1,Seq設置本身的初始化序號y。
  • 客戶端接收到服務端發送過來的響應報文段,也爲該鏈接分配緩存以及變量,同時再發送一個報文段確認創建鏈接,這時候的報文段是能夠攜帶應用層數據的,這是報文段中的相應字段:SYN設置爲0,Seq=x+1,ACK=y+1。

經過三次握手,雙方創建了鏈接,就能夠相互發送/接收數據了。那麼爲何要三次握手呢?網絡得來的答案以下:

爲何A還要發送一次確認呢?能夠二次握手嗎?

主要爲了防止已失效的鏈接請求報文段忽然又傳送到了B,於是產生錯誤。如A發出鏈接請求,但因鏈接請求報文丟失而未收到確認,因而A再重傳一次鏈接請求。後來收到了確認,創建了鏈接。數據傳輸完畢後,就釋放了鏈接,A工發出了兩個鏈接請求報文段,其中第一個丟失,第二個到達了B,可是第一個丟失的報文段只是在某些網絡結點長時間滯留了,延誤到鏈接釋放之後的某個時間纔到達B,此時B誤認爲A又發出一次新的鏈接請求,因而就向A發出確認報文段,贊成創建鏈接,不採用三次握手,只要B發出確認,就創建新的鏈接了,此時A不理睬B的確認且不發送數據,則B一致等待A發送數據,浪費資源。

四次揮手用於斷開雙方的鏈接,主要流程以下圖所示:

該內容來自這位大牛的文章,我只是作搬運工,底下內容的ACK以及ack兩個不是特別明白,看計算機網絡自頂向下中沒有解釋,不過不影響理解

  • A的應用進程先向其TCP發出鏈接釋放報文段(FIN=1,序號seq=u),並中止再發送數據,主動關閉TCP鏈接,進入FIN-WAIT-1(終止等待1)狀態,等待B的確認。
  • B收到鏈接釋放報文段後即發出確認報文段,(ACK=1,確認號ack=u+1,序號seq=v),B進入CLOSE-WAIT(關閉等待)狀態,此時的TCP處於半關閉狀態,A到B的鏈接釋放。
  • A收到B的確認後,進入FIN-WAIT-2(終止等待2)狀態,等待B發出的鏈接釋放報文段。
  • B沒有要向A發出的數據,B發出鏈接釋放報文段(FIN=1,ACK=1,序號seq=w,確認號ack=u+1),B進入LAST-ACK(最後確認)狀態,等待A的確認。
  • A收到B的鏈接釋放報文段後,對此發出確認報文段(ACK=1,seq=u+1,ack=w+1),A進入TIME-WAIT(時間等待)狀態。此時TCP未釋放掉,須要通過時間等待計時器設置的時間2MSL後,A才進入CLOSED狀態。

爲何鏈接的時候是三次握手,關閉的時候倒是四次握手?

由於當Server端收到Client端的SYN鏈接請求報文後,能夠直接發送SYN+ACK報文。其中ACK報文是用來應答的,SYN報文是用來同步的。可是關閉鏈接時,當Server端收到FIN報文時,極可能並不會當即關閉SOCKET,因此只能先回復一個ACK報文,告訴Client端,"你發的FIN報文我收到了"。只有等到我Server端全部的報文都發送完了,我才能發送FIN報文,所以不能一塊兒發送。故須要四步握手。

流量控制

一條TCP鏈接每一側的主機都會爲該鏈接創建一個接受緩存來保存數據,當TCP接收到正確的數據的時候就會放入到緩存當中,相關應用程序則會在合適的時間去緩存中讀取數據。那麼若是發送方發送數據過快致使了接受方的緩存溢出了就會形成問題。

解決該問題的方案就是流量控制,流量控制是一個速度匹配的服務,即便得發送方的發送速率和接收方應用程序的讀取速率相匹配。TCP使發送方維護一個窗口的變量來提供流量控制,就是咱們在TCP報文段結構中的接收窗口字段,代表接收方還有多少可用的緩存空間。因爲TCP爲全雙工通訊,因此接收方和發送方各有一個接收窗口。

下面簡單看個例子:

  • 剛開始的窗口大小爲5個報文段,首先發送方發送了5個報文段,而且第一個,第二個已經被確認,因此窗口前移兩個報文段
  • 發送方繼續發送數據,在受第四個報文段的確認後,發送服務端要求把接受窗口改爲4個報文段,因此窗口被縮小了。

擁塞控制

擁塞控制主要用於解決網絡擁塞的問題,網絡擁塞緣由主要在於太多的源想要以太高的速率發送數據。TCP中實現的擁塞控制主要有以下方式:

  • 慢啓動
  • 擁塞避免
  • 快速恢復和快速重傳

發送方會維護一個擁塞窗口(cwnd)來控制發送速率

慢啓動的原理以下:

當一條TCP鏈接開始的時候,cwnd的值通常設置爲一個MSS,首先傳遞一個報文段,當接收到該報文段的確認時候,cwnd值就變成2個MSS,而後發送兩個報文段,當這兩個報文段被確認後,cwnd值就變成4個MSS而後發送4個報文段,以此類推

慢啓動呈指數冪的形式增長擁塞窗口,可是也不能無限制的去增長對應的擁塞窗口,慢啓動會伴隨着一個變量共同使用:ssthresh(慢啓動閾值)。當cwnd的值等於ssthresh的時候,就會進入擁塞避免的策略當中去。

當進入擁塞避免的時候,cwnd按線性規律增加。

一條TCP鏈接有時會因等待重傳計時器的超時而空閒較長的時間,慢開始和擁塞避免沒法很好的解決這類問題,所以提出了快速重傳和快速恢復的擁塞控制方法。

快重算法機制是,丟包了,接收端重複發送丟包前的ACK,發送端每發送一個包過來,接收端就發相同的ACK回去,這個ACK是對丟包以前的確認。當接收端連續收到3個相同的ACK,它就知道發生丟包了,根據ACK序號就能重發丟的包。其並不是取消了重傳機制,只是在某些狀況下更早的重傳丟失的報文段(若是當發送端接收到三個的確認ACK時,則判定分組丟失,當即重傳丟失的報文段,而沒必要等待重傳計時器超時)。

快恢算法主要是跟着快重算法一塊兒使用的,因爲發送方如今認爲網絡極可能沒有發生擁塞,所以如今不執行慢開始算法,而是把cwnd值設置爲慢啓動閾值減半後的值,而後開始執行擁塞避免算法,是擁塞窗口的線性增大。

因此擁塞控制的基本流程是以下:

  • 先慢啓動,達到cwnd=ssthresh時,進入擁塞避免。
  • 若是發生丟包,進入擁塞發生。由於丟包有兩種不一樣處理辦法,因此擁塞發生也有兩種不一樣的處理辦法。
  1. 計算ssthresh,cwnd,從新進入慢啓動,再等到cwnd=ssthresh時,再次進入擁塞避免。
  2. 計算ssthresh,cwnd,快速重傳,再等到cwnd=ssthresh時,再次進入擁塞避免。(步驟2就稱爲快速恢復)

總結

TCP的可靠性應該是相對於UDP不可靠傳輸來講的,由於UDP提供的是不可靠的數據報服務,不保證數據報能到達接收端,可能會有丟失;另外處於傳輸層之下的IP層也是不可靠的,僅提供盡力而爲的端到端數據傳輸服務,不做任何保證。因此TCP的可靠性是指基於不可靠的IP層在傳輸層提供可靠的數據傳輸服務,主要是指傳輸數據不會損壞或丟失,並且全部數據都是按照發送順序進行傳送。實現TCP的可靠傳輸有如下機制:

  1. 校驗和(校驗數據是否損壞)
  2. 定時器(分組丟失則重傳)
  3. 序號(用於檢測丟失的分組和冗餘的分組)
  4. 確認(接收方告知發送方正確接收分組以及指望的下一個分組)
  5. 否認確認(接收方通知發送方未被正確接收的分組)
  6. 窗口和流水線(用於增長信道的吞吐量)。

參考資料

https://blog.csdn.net/u014738387/article/details/52046502

https://blog.csdn.net/mxway/article/details/42784495

《計算機網絡-自頂向下》

http://www.javashuo.com/article/p-ooymcqhd-mo.html

http://www.javashuo.com/article/p-xdjkkgbk-nc.html

http://www.javashuo.com/article/p-hvkgbelr-cs.html

相關文章
相關標籤/搜索