軟件開發速學計網:傳輸層

前言,要完整的學計網看這,韓立剛老師的課,絕對有趣,而我這是參考慕課網:編程必備基礎中的網絡篇,都是軟件的,不是很全,但是對於搞軟件的我覺得夠了。有錯請指出,謝謝

1. 概述

傳輸層中爲應用層實體提供端到端的通信功能或者說管理端到端的通信,保證了數據包的順序傳送及數據的完整性。傳輸層中主要有兩個重要的協議:TCP協議和UDP協議。

端到端是建立在點到點的基礎上,點到點通信是指的是信道間的通信,而端到端指的是應用程序(進程)之間的通信。

在操作系統中也有進程的概念,那些進程中的通信,比如共享內存,UNIX域套接字是單機的,即僅限於一臺主機內通信,不能跨網絡。而網絡通信,比如瀏覽器訪問網頁,需要通過網絡去該網站的後臺取得數據,這就是網絡中進程間的通信。

常使用端口(Port)來標記不同的網絡進程。端口(Port)使用16比特位表示(0~65535)。常見的網絡進程端口有:(FTP:21)、(HTTP:80)、(HTTPS:443)、(DNS:53)等。

2. UDP協議

UDP(User Datagram Protocal,用戶數據報協議):數據報是應用層傳輸過來的數據,UDP不會對該數據報做任何處理,會封裝到協議裏面然後傳輸出去。

在這裏插入圖片描述

2.1 UDP的組成

在這裏插入圖片描述

  • 源端口號:源機器使用的網絡進程。
  • 目的端口號:目的機器使用的網絡進程。
  • UDP長度:指的是UDP的首部和UDP數據的總長。首部長度固定爲8字節。
  • UDP校驗和:由發送端計算和存儲,由接收端校驗。解決數據正確性問題。

2.2 UDP的特點

  • UDP是無連接協議,即不需要建立連接即可傳輸數據。跟電話系統相反。
  • 正因爲是無連接的協議,所以UDP不能保證可靠的交互數據,即無法保證傳輸的數據是否會丟失。
  • UDP是面向報文傳輸的,就是UDP數據報。(TCP就不是)
  • UDP沒有擁塞控制。它不會感受到網絡是否擁塞,所以總是發送數據。
  • UDP首部開銷非常小,總共才8個字節。

在這裏插入圖片描述

3. TCP協議

TCP(Transmission Control Protocol,傳輸控制協議):是爲了在不可靠的互聯網絡上提供可靠的端到端字節流而專門設計的一個傳輸協議。

3.1 TCP的特點

  • TCP是面向連接的協議,即通信時需要先建立連接。比如打電話。
  • TCP的一個連接有兩端(端到端),而不考慮中間網段和節點。比如打電話的雙方。
  • TCP提供可靠的傳輸服務
  • TCP協議提供全雙工的通信。全雙方就是雙方可以同時進行對話(發送和接收)。
  • TCP是面向字節流的協議。字節流就是流入進程或流出進程的字節序列。把數據拆分成幾段連續字節流來傳輸,在接收端把字節流組合起來。

在這裏插入圖片描述

3.2 TCP的組成(只看首部)

在這裏插入圖片描述

  • 序號(seq):因爲數據會拆分成幾段連續字節流後封裝到TCP數據報,所以需要記錄拆分後每個TCP數據報中的第一個字節的序列號(在原先未拆分前的位置),它的範圍爲:0~(2^32)-1,在TCP報文中一個字節一個序號。就比如 helloworld,這一串字節流,假設被拆分成了三個 TCP 報文段,第一個報文段攜帶了 hel,第二個報文段攜帶了 lowo,第三個報文段攜帶了 rld,這三個報文段不一定是按照順序送到對端的,那麼對端收到這三個段是如何確定他們的順序的呢?此時序號的意義就體現在這裏。參考:TCP的序號

(TCP至少有20個字節的首部)
在這裏插入圖片描述

  • 確認號(ack,與大寫ACK不一樣,看下面的TCP標記):期望收到的下一個數據報中數據的首字節序號,它的範圍爲:0~(2^32)-1。假設確認號爲N,則表示N-1序號的數據都已經收到了。前面這句話更準確的表示意義是:假設接收方確認接收到了1到n-3、n-2、n-1字節,那麼接收方就會返回一個確認號爲n,表示n之前的字節都已經收到,現在期望接收第n個字節,即是對接收到的數據的最高序列號的確認。好好理解這個例子,比如傳1,2,3,而接收方只接收了1,3,這時如果返回確認號4(表示4之前的都收到了)那就是出錯了吧,所以接收方返回確認號一定爲2。
  • 數據偏移:佔4位(0~15),該字段的值是TCP首部(包括選項)長度除以4。表示傳輸數據偏移TCP首部的距離,主要是TCP選項導致的,因爲TCP選項是可選,不知道內容是多少。數據偏移的範圍:20字節(固定,即前5行,每行有4個字節,即4*5)到60字節(最大有15行包括固定部分和可選部分,每行4個字節,即15*4)
  • TCP標記:佔6位,每位各有不同含義。(重要,需要記住)

在這裏插入圖片描述

  • 窗口(cwnd):佔16位(0~(2^16)-1),指明對方可以發送的數據量,用於控制TCP連接中數據傳輸的速率。比如確認號爲501,窗口爲1000,則501~1501該範圍的字節都可以接收。
  • 檢驗和:由發送端計算和存儲,由接收端校驗。解決數據正確性問題。
  • 緊急指針:當TCP標記中URG=1時,才啓動。該指針指定緊急數據在報文的位置。

4. 可靠傳輸的基本原理

4.1 停止等待協議

如圖:理想情況下的傳輸,消息1發送完,停止發送,等待確認1,類似消息2,3也是。
在這裏插入圖片描述

以下是三種出差錯情況:

  1. 發送的消息在路上丟失了
    在這裏插入圖片描述
  2. 確認的消息在路上丟失了
    在這裏插入圖片描述
  3. 確認的消息很久纔到
    在這裏插入圖片描述

其中,通過超時重傳來保證可靠傳輸。

TCP有四個定時器,先學一種:重傳計時器:每發送一個消息,都需要設置一個計時器,該計時器設置一個時間,如果信息在規定時間內還沒收到接收方的確認消息,則可以重傳。

停止等待協議是最簡單的可靠傳輸協議,但對信道的利用效率不高。

4.2 ARQ協議

ARQ(Automatic Repeat reQuest,自動重傳請求)。前面的停止等待協議,每次只能發送單個信息和確認效率低下,現在提出了ARQ協議來進行批量發送和確認,該協議有兩個精髓:滑動窗口和累計確認

  • 滑動窗口:滑動窗口的大小意味着接收方還有多大的緩衝區可以用於接收數據,即接收窗口。發送方可以通過滑動窗口的大小來確定應該發送多少字節的數據,即發送窗口。接收窗口和發送窗口的大小可以不同。

現在,如圖,發送方窗口內的序列號可以代表了那些已經被髮送,但是還沒有被確認的幀,或者是那些可以被髮送的幀。現在發送方發送了第一個和第二個字節。
在這裏插入圖片描述
只要接收到確認消息,那麼窗口會繼續滑動,把還沒進入窗口的字節加進來。
在這裏插入圖片描述

但是每一個報文都需要確認的話,確認消息的開銷很大,所以提出了不需要對每個報文進行確認,採用累計確認方法。假設1到5發送,如果接收方收到了1到5,那麼就直接返回5,表示下次接收時是第5個字節。
在這裏插入圖片描述
那麼就把窗口滑動5格。
在這裏插入圖片描述

  • 累計確認:即是對接收到的數據的最高序列號的確認。好好理解這個例子,比如傳1,2,3,而接收方只接收了1,3,這時如果返回確認號4(表示4之前的都收到了)那就是出錯了吧,所以接收方是返回確認號一定爲2。跟前面的確認號的意義一樣。

有了累計確認就不用一個一個去確認。

所以連續ARQ協議比起停止等待協議的信道利用率更高,批量傳輸。

5. TCP協議的可靠傳輸

TCP的可靠傳輸基於ARQ協議,TCP的滑動窗口以字節爲單位,以超時重傳來保證可靠性,即接收方需要發送確認消息給發送方,如果一定時間內發送方沒有收到確認消息,則認爲消息沒有到達接收方,重新發送數據。

如圖:實際中的窗口大小可容納上千個字節甚至更多。一個信息段可分成:已經確認的字節序號,允許發送的字節序號,不允許發送的字節序號。
在這裏插入圖片描述

下面的例子跟前面的例子一樣,發送了四個字節,現在已經確認前兩個字節已經接收,則窗口會滑動。
在這裏插入圖片描述

當然,如果可用窗口爲0,而已發送的還未確認則不會滑動。
在這裏插入圖片描述

其實,發送端每發送一個報文段,就啓動一個重傳定時器並等待確認信息;接收端成功接收新數據後返回確認信息。若在定時器超時前數據未能被確認,TCP就認爲報文段中的數據已丟失或損壞,需要對報文段中的數據重新組織和重傳。這就是超時重傳技術。注意:重傳的次數是有限的,不可能無限重傳。

在這裏插入圖片描述

如果每次都重傳整個數據報那樣就影響效率,因爲有些已經確認收到了,所以可以選擇重傳,即選中某些字節範圍重新傳輸,然後接收方將未按序號到達的數據包先放於緩衝區內,等待它前面的序號包到達後在組織。當然也可能出現全部都丟失的情況那就需要重發整個數據段。

具體請參考:TCP報文到達確認(ACK)機制
,裏面說的未按序到達的例子中通常有兩種處理方式:第一種就是對沒有按序號到達的報文直接丟棄,這就需要重發整個數據報,第二種就是選擇重傳。他的例子:

發送方連續發送了每個報文中100個字節的TCP數據報,其序號分別是1,101,201,…,701。假如其它7個數據報都收到了,而201這個數據報沒有收到,則接收端應當對1和101這兩個數據報進行確認(累計確認),並將數據遞交給相關的應用進程,301至701這5個數據報則應當放於緩衝區,等到201這個數據報到達後,然後按序將201至701這些數據報遞交給相關應用進程,並對701數據報進行確認,確保了應用進程級的TCP數據的按序到達。

選擇重傳是利用TCP首部中的序號,首部使用TCP選項來存儲選擇所需重傳的序號,因爲重傳並不是每次都要的。TCP選項最多可存儲40個字節,也就是10個序號,但是這重傳也太小了吧,實際上它是存儲序號的邊界。所以選擇重傳實際上是選擇一段連續字節來重傳。

(實際上每次發送的字節數是很多的,即滑動窗口很大,不是上面的例子中每次發送那麼少)
在這裏插入圖片描述

6. TCP協議的流量控制

流量控制是TCP特有的功能。就是接收方希望發送方發送的數據慢一下,不要一直一直髮送,接收方都接收不了太多,即讓發送發的發送速率不要太快。流量控制是使用滑動窗口來實現的

結合TCP組成中首部的窗口,指明對方可以發送的數據量。
在這裏插入圖片描述

假設確認號是501,窗口爲1000,則表示501~1501該範圍的字節都可以接收。

正常情況下:
在這裏插入圖片描述

如圖,當發送方收到接收方的窗口爲0時,發送方一直等待接收方把窗口擴大以便傳輸數據,現在接收方擴大窗口,然後把窗口擴大的信息發送給發送方,此時在發送時卻丟失了,而接收方也在等待發送方發送信息。此時雙方都在互相等待出現了死鎖。所以發送發需要一個計時器來詢問接收方窗口是不是調大了,該定時器叫做計時器*。
在這裏插入圖片描述

堅持計時器:

  • 當接收到窗口爲0的消息,則啓動堅持計時器。
  • 堅持計時器每隔一段時間發送一個窗口探測報文,即去詢問接收方窗口有沒有調大。

7. TCP協議的擁塞控制

與UDP相反,TCP協議有擁塞控制,就是我們常說的塞車情況。

先來說說根源:在數據報傳輸時,經過很多設備,但經過的設備可能性能差距不一樣或者速率不一樣,這可能會造成網絡傳輸的瓶頸(就好像在很低配置的主機運行需要高配置的3D遊戲的那種情況)。也就是導致擁塞。

擁塞控制與流量控制:

  • 流量控制考慮的是點對點的通信量的控制,強調TCP連接雙方的發送-接收速率
  • 擁塞控制考慮的是整個網絡,是全局性的考慮,控制強調網絡環境的狀態

擁塞需要去判斷,方法非常粗暴,就是:報文超時則認爲可能是擁塞。因爲有可能某些路由器處理不過來導致報文超時。當然插網線,自己網絡有問題有可能導致報文超時。所以只需要知道報文超時是可以判斷擁塞的一個方法

擁塞控制中會啓動四個算法

  • 慢啓動算法:由小到大逐漸增加發送數據量,每收到一個報文確認,就加一。增長是以指數增長。比如1,2,4,8,16這樣。增長到慢啓動閾值(ssthresh),然後就啓動第二個算法。
  • 擁塞避免算法,維護一個擁塞窗口的變量,該變量大於慢啓動閾值。只要網絡不擁塞(報文不超時),就試探着擁塞窗口調大。比如前面假設16是慢啓動閾值,則會慢慢調到17,18,19這樣,直到發生擁塞。
  • 快重傳算法:首先要求接收方每收到一個失序的報文段就立即發出重複確認(爲的是使發送方及早的知道有報文段沒有到達對方)而不要等到自己發送數據時才捎帶確認。轉載,老師只是講了前面兩個算法
  • 快恢復算法:當發送方連續收到三個重複確認時,就執行“乘法減小”算法,把ssthresh門限減半。但是接下去並不執行慢開始算法。考慮到如果網絡出現擁塞的話就不會收到好幾個重複的確認,所以發送方現在認爲網絡可能沒有出現擁塞。所以此時不執行慢開始算法,而是將cwnd(窗口)設置爲ssthresh的大小,然後執行擁塞避免算法。轉載

如果擁塞發送了,就降低發送的數據量。

擁塞控制的實現:TCP連接的發送方可以感知網絡環境的狀態並做出反應。發送端使用慢啓動算法、擁塞避免算法、快恢復算法、快重傳算法。

在這裏插入圖片描述

8. TCP的三次握手建立連接

回顧前面的TCP標記,該標記中有三個需要在建立連接時使用的:ACK,SYN,FIN。

三次握手部分參考:TCP的三次握手與四次揮手(詳解+動圖):可以看看這個。需要知道的兩點:TCP規定,SYN報文段(SYN=1的報文段)不能攜帶數據,但需要消耗掉一個序號;ACK報文段可以攜帶數據,但是如果不攜帶數據則不消耗序號。

(說接收方或服務器都可以,說發送方或客戶端都可以)
三次握手:

  • 第一次握手:接收方是時刻保持監聽狀態來接收報文(LISTEN)。發送方主動的向接收方發送一個SYN報文,即TCP標記中SYN=1,表示這是一個連接請求的報文,並且帶上該報文的序號(seq,假設值爲x),然後等待迴應,此時發送方進入同步已發送狀態(SYNC-SENT)。
  • 第二次握手:接收方收到SYN報文,會被動地打開TCP連接,同時給發送方也發送一個SYN報文,並且TCP標記中ACK和SYN都爲1,和序號(seq,假設值爲y)、確認號(ack,則ack=x+1)。此時接收方進入同步已接收狀態(SYNC-RCVD)
  • 第三次握手:發送方繼續向接收方繼續發送一個ACK報文,即TCP標記中ACK=1,和seq(seq=x+1)、ack(ack=y+1)。此時發送方就進入建立連接狀態(ESTABLISHED),當接收方收到報文ACK後,也進入建立連接狀態(ESTABLISHED)。至此就可以通信了。

在這裏插入圖片描述

面試常問的一個問題:爲什麼要有第三次握手? 前兩個其實已經可以來建立連接了啊?

因爲:來防止已經失效的連接請求報文又發送到對方導致想再建立一個連接,會引起錯誤。

解釋:第一個報文發送後超時了,重新發送第二個報文。那麼現在第一個報文就是屬於失效的連接請求報文。
在這裏插入圖片描述
現在假設只有兩次握手引發的後果:假設第一個報文發送後超時了(但假設未丟失,只是太慢了),所以會重新發送第二個相同報文。第二個報文很快到達接收方,建立連接。但是過一段時間,突然接收到了第一個報文,本來該報文已經是失效的,但是因爲兩次握手,又必須建立連接。一次通信居然連接了兩個連接,這可能會導致錯誤和資源的浪費。
在這裏插入圖片描述
所以如果採用3次握手,那麼失效的報文在第三次握手時,發送方並不會發送確認消息了(因爲已經建立連接了)。而接收方又沒有收到發送方的迴應,則就不會再建立連接。

9. TCP的四次揮手釋放連接

四次揮手也可叫四次釋放或四次分手。

(TCP規定,FIN報文段即使不攜帶數據,也要消耗一個序號。)

  • 第一次揮手:發送方主動發送連接釋放FIN報文,即TCP標記中的FIN=1,並帶上一個序號(假設seq=u),並停止發送數據。然後發送方就進入了連接結束的第一個等待狀態(FIN-WAIT-1)
  • 第二次揮手:接收方被動收到FIN報文,發出ACK報文,該報文TCP標記中的ACK=1,並帶上一個序號(假設seq=v)和確認好(ack=u+1)。此時接收方就處於關閉等待狀態(CLOSE-WAIT),但接收方還是可以向發送方發送數據的,因爲可能接收方有些數據還沒發完,注意是發送方主動要釋放連接的。所以發送方在收到ACK報文後還不能關閉連接,此時處於終止連接的第二個等待狀態(FIN-WAIT-2)。
  • 第三次揮手:當接收方發送完數據後,接收方就發送一個FIN報文,即TCP標記中的FIN=1,並且ACK也爲1,攜帶seq=w和ack=u+1。這是爲了對第一次揮手的報文再進行確認。所以此時接收方進入了最後確認狀態(LAST-ACK)。
  • 第四次揮手:當發送方接收到FIN報文後,也發出ACK報文,攜帶seq=u+1和ack=w+1。此時發送方會觸發一個等待計時器(TIME-WAIT),等待一段時間確認沒有問題後,發送方就進入關閉連接狀態(CLOSE)。當接收方接收到ACK報文後也進入關閉連接狀態(CLOSE)。

在這裏插入圖片描述

每次揮手都會有一個重傳計時器。

MSL:Max Segment Lifetime,即最長報文段壽命。對於網絡來說,MSL通常是2分鐘。

等待計時器:等待2倍的MSL。連接會佔用端口,只有等待計時器結束後才釋放端口。建立在我們主動去釋放連接的基礎上。

典型問題:爲什麼要等待2MSL?

答:有兩點。

  • 第一點:因爲最後一次揮手發送的報文是沒有確認的,所以確保發送方的ACK可以到達接收方。所以2MSL是報文可以在網絡中存活的時間。如果接收方在2MSL時間內沒有收到發送方的ACK報文,則認爲接收方的第三次揮手是有問題的,需要重發第三次揮手的報文。
  • 第二點:確保當前連接的所有報文都已經過期了。因爲最後一次報文都需要等待2MSL,那其他的報文一定超過了2MSL的時間了。防止出現防止已經失效的連接請求報文又發送到對方導致想再建立一個連接,會引起錯誤。(跟前面第三次握手的意義一樣。)

10. 4個計時器(重要)

目前已經知道了3個計時器:重傳計時器,堅持計時器,等待計時器。還有最後一個,即保活計時器。

10.1 重傳計時器

每發送一個消息,都需要設置一個計時器,該計時器設置一個時間,如果信息在規定時間內還沒收到接收方的確認消息,則重傳。

每次重傳都會再設置一個計時器。並且重傳是有限次數的。

需要注意的是,發送端在超時定時器撤銷之前,必須繼續緩存已發送未確認的報文,直到發送端收到了來自接收端的確認。

10.2 堅持計時器

是使用滑動窗口進行流量控制的時候而設置的。這時需要理解“零窗口通知”的情況。

“零窗口通知”:接收端通過調整接收窗口的大小可以控制發送端的發送速度,當接收端把接收窗口調小時,那麼發送端就會調小發送的流量。
這就可能產生一種情況,就是接收端的緩存區已經滿了,這個時候接收端會給發送端發送一個“零窗口”的消息,表示說“當前我已經沒有餘力處理更多的數據了”,這就是“零窗口通知”的情況。

當出現這種情況的時候,雙方都會陷入等待的狀態,發送端等待接收端的窗口調大,接收端等待發送端發送的數據。當接收端窗口可以調大的時候,接收端會發送窗口調大的信息給發送端,但是這個消息是不可靠的,也即是這個消息可能會在傳輸中丟失,並且不會被感知到丟失和重傳。

如果這個消息在發送過程中丟失的話,那麼發送端和接收端就會進入死鎖狀態,因爲接收端認爲“我已經把窗口調大的消息發送出去了,發送端理應發送新的消息給我纔對”,所以接收端會一直等待發送端的消息;而發送端因爲沒有收到窗口調大的消息,則認爲“接收端還沒有調大窗口,因此我不能發送”,發送端也會一直等待。
因此爲了解決這個問題,當發送端收到窗口爲零的消息之後,會啓動一個堅持定時器來週期性主動的向接收方查詢,以便發現窗口是否增大,這個就是堅持定時器的作用。

10.3 等待計時器

由主動關閉TCP連接的一方設置的,當主動關閉TCP連接的一方收到來自對方的FIN報文的時候(第三次揮手),則認爲對方也可以關閉TCP連接,這個時候主動關閉TCP連接的一方發送一個消息確認的報文(第四次揮手),並啓動這個時間等待計時器,這個計時器會等待2倍MSL的時間,MSL(Max Segment Lifetime),最大報文段壽命。

假設主動關閉方爲A。
這個定時器主要是爲了正確關閉一個TCP連接而考慮的,這主要是爲了保證A在對最後一個FIN報文(第三次揮手)發送確認的報文可以到達B。

當A發出這個報文之後,就會啓動2MSL計時器,注意,這個報文是有可能在網絡傳輸過程中丟失的,如果B收不到這個確認,那麼B會重新發送一次FIN報文,A會重新收到這個報文並重傳一次最後的確認,並重新啓動2MSL計時器,直到雙方正常結束TCP連接。2MSL時間可以保證當B沒有收到確認時,B可以再次發出FIN報文,並且A可以再次收到並重新發送確認,所以2MSL的時間可以保證連接正常結束。

10.4 保活計時器

爲了保活TCP連接而設計的,保活計時器可以防止TCP連接的兩端出現長時期的空閒,當一方出現狀態變化或故障時,另一方沒有察覺的情況。

設想連接雙方在建立連接後,只傳輸了一些數據,然後就都保持靜默了,雙方也都沒有關閉連接(這種情況經常存在),如果這個時候其中一方已經故障,那麼這個連接將會永遠被打開,如果被連接的一方是服務端的話,那將浪費很多服務端的資源。

因此爲了解決這個問題,服務端一般都會設置一個保活定時器,每次收到對方的數據則重置這個定時器,如果定時器超時,服務端則發送探測報文段,探測客戶端是否還在線,如果沒有收到響應的話,那麼則認爲客戶端已經斷開連接了,因此服務端也會終止這個連接。

11. 套接字

套接字的格式就是:{IP:Port},即一個IP地址和一個端口號。可以在網絡中指定一臺主機中的具體進程是什麼。因爲IP地址是網絡中唯一的,端口號是主機進程唯一的。

套接字(Socket),表示TCP連接的一端。通過套接字可以進行數據發送或接收。

TCP是兩端連接的,那麼就需要兩個套接字。即:TCP={Socket1:Socket2}={{IP:Port},{IP:Port}}。

在java中有一個網絡編程概念,使用Socket類,該類說的就是這個套接字。所以一般網絡編程是通過傳輸層進行傳輸和接收數據。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章