天天看點

28張圖,Linux netstat指令詳解

作者:微笑橙子mR

做IT相關的工作,肯定都離不開網絡,網絡中最重要的協定是TCP。無論是實際工作還是筆試面試,你看哪裡能少得了TCP?

我看過RFC中與TCP相關的文檔,也看過linux中TCP相關的源碼,也看過不少架構中的TCP相關的代碼,對TCP是有點感覺了。

一直想找個時間來分享下TCP相關的知識,如果大家有疑問,歡迎互相交流。其實,搞透了TCP之後,發現它也就那麼回事。

考慮最簡單的情況:兩台主機之間的通信。這個時候隻需要一條網線把兩者連起來,規定好彼此的硬體接口,如都用USB、電壓10v、頻率2.4GHz等,這一層就是實體層,這些規定就是實體層協定 。

28張圖,Linux netstat指令詳解

我們當然不滿足于隻有兩台電腦連接配接,是以我們可以使用交換機把多個電腦連接配接起來,如下圖:

28張圖,Linux netstat指令詳解

這樣連接配接起來的網絡,稱為區域網路,也可以稱為以太網(以太網是區域網路的一種)。在這個網絡中,我們需要辨別每個機器,這樣才可以指定要和哪個機器通信。這個辨別就是硬體位址MAC。硬體位址随機器的生産就被确定,永久性唯一。在區域網路中,我們需要和另外的機器通信時,隻需要知道他的硬體位址,交換機就會把我們的消息發送到對應的機器。

這裡我們可以不管底層的網線接口如何發送,把實體層抽離,在他之上建立一個新的層次,這就是資料鍊路層 。

我們依然不滿足于區域網路的規模,需要把所有的區域網路聯系起來,這個時候就需要用到路由器來連接配接兩個區域網路:

28張圖,Linux netstat指令詳解

但是如果我們還是使用硬體位址來作為通信對象的唯一辨別,那麼當網絡規模越來越大,需要記住所有機器的硬體位址是不現實的;同時,一個網絡對象可能會頻繁更換裝置,這個時候硬體位址表維護起來更加複雜。這裡使用了一個新的位址來标記一個網絡對象:IP位址 。

通過一個簡單的寄信例子來了解IP位址。

我住在北京市,我朋友A住在上海市,我要給朋友A寫信:

  1. 寫完信,我會在信上寫好我朋友A的位址,并放到北京市郵局(給資訊附加目标IP位址,并發送給路由器)
  2. 郵局會幫我把信運輸到上海市當地郵局(資訊會經過路由傳遞到目标IP區域網路的路由器)
  3. 上海市當地路由器會幫我把信交給朋友A(區域網路内通信)

是以,這裡IP位址就是一個網絡接入位址(朋友A的住址),我隻需要知道目标IP位址,路由器就可以把消息給我帶到。在區域網路中,就可以動态維護一個MAC位址與IP位址的映射關系,根據目的IP位址就可以尋找到機器的MAC位址進行發送 。

這樣我們不需管理底層如何去選擇機器,我們隻需要知道IP位址,就可以和我們的目标進行通信。這一層就是網絡層。網絡層的核心作用就是 提供主機之間的邏輯通信 。這樣,在網絡中的所有主機,在邏輯上都連接配接起來了,上層隻需要提供目标IP位址和資料,網絡層就可以把消息發送到對應的主機。

一個主機有多個程序,程序之間進行不同的網絡通信,如邊和朋友開黑邊和女朋友聊微信。我的手機同時和兩個不同機器進行通信。那麼當我的手機收到資料時,如何區分是微信的資料,還是王者的資料?那麼就必須在網絡層之上再添加一層:運輸層 :

28張圖,Linux netstat指令詳解

運輸層通過socket(套接字),将網絡資訊進行進一步的拆分,不同的應用程序可以獨立進行網絡請求,互不幹擾。這就是運輸層的最本質特點:提供程序之間的邏輯通信 。這裡的程序可以是主機之間,也可以是同個主機,是以在android中,socket通信也是程序通信的一種方式。

現在不同的機器上的應用程序之間可以獨立通信了,那麼我們就可以在計算機網絡上開發出形形式式的應用:如web網頁的http,檔案傳輸ftp等等。這一層稱為應用層。

應用層還可以進一步拆分出表示層、會話層,但他們的本質特點都沒有改變:完成具體的業務需求 。和下面的四層相比,他們并不是必須的,可以歸屬到應用層中。

最後對計網分層進行小結:

28張圖,Linux netstat指令詳解
  1. 最底層實體層,負責兩個機器之間通過硬體的直接通信;
  2. 資料鍊路層使用硬體位址在區域網路中進行尋址,實作區域網路通信;
  3. 網絡層通過抽象IP位址實作主機之間的邏輯通信;
  4. 運輸層在網絡層的基礎上,對資料進行拆分,實作應用程序的獨立網絡通信;
  5. 應用層在運輸層的基礎上,根據具體的需求開發形形式式的功能。

這裡需要注意的是,分層并不是在實體上的分層,而是邏輯上的分層。通過對底層邏輯的封裝,使得上層的開發可以直接依賴底層的功能而無需理會具體的實作,簡便了開發。

這種分層的思路,也就是責任鍊設計模式,通過層層封裝,把不同的職責獨立起來,更加友善開發、維護等等。okHttp中的攔截器設計模式,也是這種責任鍊模式。

/ 運輸層 /

本文主要是講解TCP,這裡需要增加一些運輸層的知識。

本質:提供程序通信

28張圖,Linux netstat指令詳解

在運輸層之下的網絡層,是不知道該資料包屬于哪個程序,他隻負責資料包的接收與發送。運輸層則負責接收不同程序的資料交給網絡層,同時把網絡層的資料拆分交給不同的程序。從上往下彙聚到網絡層,稱為多路複用,從下往上拆分,稱為多路拆分 。

運輸層的表現,受網絡層的限制。這很好了解,網絡層是運輸層的底層支援。是以運輸層是無法決定自己帶寬、時延等的上限。但可以基于網絡層開發更多的特性:如可靠傳輸。網絡層隻負責盡力把資料包從一端發送到另一端,而不保證資料可以到達且完整。

底層實作:socket

前面講到,最簡單的運輸層協定,就是提供程序之間的獨立通信 ,但底層的實作,是socket之間的獨立通信 。在網絡層中,IP位址是一個主機邏輯位址,而在運輸層中,socket是一個程序的邏輯位址;當然,一個程序可以擁有多個socket。應用程序可以通過監聽socket,來擷取這個socket接受到的消息。

28張圖,Linux netstat指令詳解

socket并不是一個實實在在的東西,而是運輸層抽象出來的一個對象。運輸層增加了端口這個概念,來區分不同的socket。端口可以了解為一個主機上有很多的網絡通信口,每個端口都有一個端口号,端口的數量由運輸層協定确定。

不同的運輸層協定對socket有不同的定義方式。在UDP協定中,使用目标IP+目标端口号來定義一個socket;在TCP中使用目标IP+目标端口号+源IP+源端口号來定義一個socket。我們隻需要在運輸層封包的頭部附加上這些資訊,目标主機就會知道我們要發送給哪個socket,對應監聽該socket的程序就可獲得資訊。

運輸層協定

運輸層的協定就是大名鼎鼎的TCP和UDP。其中,UDP是最精簡的運輸層協定,隻實作了程序間的通信;而TCP在UDP的基礎上,實作了可靠傳輸、流量控制、擁塞控制、面向連接配接等等特性,同時也更加複雜。

當然除此之外,還有更多更優秀的運輸層協定,但目前廣為使用的,就是TCP和UDP。UDP在後面也會總結到。

/ TCP協定首部 /

TCP協定,表現在封包上,就是會在應用層傳輸下來的資料前附加上一個TCP首部,這個首部附加了TCP資訊,先來整體看一下這個首部的結構:

28張圖,Linux netstat指令詳解

這張圖是來自一位大學老師的課件, 非常好用,是以一直拿來學習。最下面部分表示了封包之間的關系,TCP資料部分就是應用層傳下來的資料。

TCP首部固定長度是20位元組,下面還有4位元組是可選的。内容很多,但其中有一些我們比較熟悉的:源端口,目标端口。嗯?socket不是還需要IP進行定位嗎?IP位址在網絡層被附加了。其他的内容後面都會慢慢講解,作為一篇總結文章,這裡放出查閱表,友善複習:

28張圖,Linux netstat指令詳解
28張圖,Linux netstat指令詳解

選項字段中包含以下其他選項:

28張圖,Linux netstat指令詳解

講完下面内容,再回來看這些字段就熟悉了。

/ TCP面向位元組流特性 /

TCP并不是把應用層傳輸過來的資料直接加上首部然後發送給目标,而是把資料看成一個位元組 流,給他們标上序号之後分部分發送。這就是TCP的 面向位元組流 特性:

28張圖,Linux netstat指令詳解
  • TCP會以流的形式從應用層讀取資料并存放在自己的發送緩存區中,同時為這些位元組标上序号
  • TCP會從發送方緩沖區選擇适量的位元組組成TCP封包,通過網絡層發送給目标
  • 目标會讀取位元組并存放在自己的接收方緩沖區中,并在合适的時候傳遞給應用層

面向位元組流的好處是無需一次存儲過大的資料占用太多記憶體,壞處是無法知道這些位元組代表的意義,例如應用層發送一個音頻檔案和一個文本檔案,對于TCP來說就是一串位元組流,沒有意義可言,這會導緻粘包以及拆包問題,後面講。

/ 可靠傳輸原理 /

前面講到,TCP是可靠傳輸協定,也就是,一個資料交給他,他肯定可以完整無誤地發送到目标位址,除非網絡炸了。他實作的網絡模型如下:

28張圖,Linux netstat指令詳解

對于應用層來說,他就是一個可靠傳輸的底層支援服務;而運輸層底層采用了網絡層的不可靠傳輸。雖然在網絡層甚至資料鍊路層就可以使用協定來保證資料傳輸的可靠性,但這樣網絡的設計會更加複雜、效率會随之降低。把資料傳輸的可靠性保證放在運輸層,會更加合适。

可靠傳輸原理的重點總結一下有:滑動視窗、逾時重傳、累積确認、選擇确認、連續ARQ 。

停止等待協定

要實作可靠傳輸,最簡便的方法就是:我發送一個資料包給你,然後你跟我回複收到,我繼續發送下一個資料包。傳輸模型如下:

28張圖,Linux netstat指令詳解

這種“一來一去”的方法來保證傳輸可靠就是停止等待協定(stop-and-wait)。不知道還記不記得前面TCP首部有一個ack字段,當他設定為1的時候,表示這個封包是一個确認收到封包。

然後再來考慮一種情況:丢包。網絡環境不可靠,導緻每一次發送的資料包可能會丢失,如果機器A發送了資料包丢失了,那麼機器B永遠接收不到資料,機器A永遠在等待。解決這個問題的方法是:逾時重傳 。當機器A發出一個資料包時便開始計時,時間到還沒收到确認回複,就可以認為是發生了丢包,便再次發送,也就是重傳。

但重傳會導緻另一種問題:如果原先的資料包并沒有丢失,隻是在網絡中待的時間比較久,這個時候機器B會受到兩個資料包,那麼機器B是如何辨識這兩個資料包是屬于同一份資料還是不同的資料?這就需要前面講過的方法:給資料位元組進行編号。這樣接收方就可以根據資料的位元組編号,得出這些資料是接下來的資料,還是重傳的資料。

在TCP首部有兩個字段:序号和确認号,他們表示發送方資料第一個位元組的編号,和接收方期待的下一份資料的第一個位元組的編号。前面講到TCP是面向位元組流,但是他并不是一個位元組一個位元組地發送,而是一次截取一整段。截取的長度受多種因素影響,如緩存區的資料大小、資料鍊路層限制的幀大小等。

連續ARQ協定

停止等待協定已經可以滿足可靠傳輸了,但有一個緻命缺點:效率太低。發送方發送一個資料包之後便進入等待,這個期間并沒有幹任何事,浪費了資源。解決的方法是:連續發送資料包。模型如下:

28張圖,Linux netstat指令詳解

和停止等待最大的不同就是,他會源源不斷地發送,接收方源源不斷收到資料之後,逐一進行确認回複。這樣便極大地提高了效率。但同樣,帶來了一些額外的問題:

發送是否可以無限發送直到把緩沖區所有資料發送完?不可以。因為需要考慮接收方緩沖區以及讀取資料的能力。如果發送太快導緻接收方無法接受,那麼隻是會頻繁進行重傳,浪費了網絡資源。是以發送方發送資料的範圍,需要考慮到接收方緩沖區的情況。這就是TCP的流量控制 。解決方法是:滑動視窗 。基本模型如下:

28張圖,Linux netstat指令詳解
  • 發送方需要根據接收方的緩沖區大小,設定自己的可發送視窗大小,處于視窗内的資料表示可發送,之外的資料不可發送。
  • 當視窗内的資料接收到确認回複時,整個視窗會往前移動,直到發送完成所有的資料

在TCP的首部有一個視窗大小字段,他表示接收方的剩餘緩沖區大小,讓發送方可以調整自己的發送視窗大小。通過滑動視窗,就可以實作TCP的流量控制,不至于發送太快,導緻太多的資料丢失。

連續ARQ帶來的第二個問題是:網絡中充斥着和發送資料包一樣資料量的确認回複封包,因為每一個發送資料包,必須得有一個确認回複。提高網絡效率的方法是:累積确認 。接收方不需要逐個進行回複,而是累積到一定量的資料包之後,告訴發送方,在此資料包之前的資料全都收到。例如,收到 1234,接收方隻需要告訴發送方我收到4了,那麼發送方就知道1234都收到了。

第三個問題是:如何處理丢包情況。在停止等待協定中很簡單,直接一個逾時重傳就解決了。但,連續ARQ中不太一樣。例如:接收方收到了 123 567,六個位元組,編号為4的位元組丢失了。按照累積确認的思路,隻能發送3的确認回複,567都必須丢掉,因為發送方會進行重傳。這就是GBN(go-back-n) 思路。

但是我們會發現,隻需要重傳4即可,這樣不是很浪費資源,是以就有了:選擇确認SACK 。在TCP封包的選項字段,可以設定已經收到的封包段,每一個封包段需要兩個邊界來進行确定。這樣發送方,就可以根據這個選項字段隻重傳丢失的資料了。

可靠傳輸小結

到這裡關于TCP的可靠傳輸原理就已經介紹的差不多。最後進行一個小結:

  • 通過連續ARQ協定與發送-确認回複模式來保證每一個資料包都到達接收方
  • 通過給位元組編号的方法,來标記每一個資料是屬于重傳還是新的資料
  • 通過逾時重傳的方式,來解決資料包在網絡中丢失的問題
  • 通過滑動視窗來實作流量控制
  • 通過累積确認+選擇确認的方法來提高确認回複與重傳的效率

當然,這隻是可靠傳輸的冰山一角,感興趣可以再深入去研究(和面試官聊天已經差不多了[狗頭])。

/ 擁塞控制 /

擁塞控制考慮的是另外一個問題:避免網絡過分擁擠導緻丢包嚴重,網絡效率降低 。

拿現實的交通舉例子:

高速公路同一時間可通行的汽車數量是一定的,當節假日時,就會發生嚴重的堵車。在TCP中,資料包逾時,會進行重傳,也就是會進來更多的汽車,這時候更堵,最後導緻的結果就是:丢包-重傳-丢包-重傳。最後整個網絡癱瘓了。

這裡的擁塞控制和前面的流量控制不是一個東西,流量控制是擁塞控制的手段:為了避免擁塞,必須對流量進行控制。(網絡工程師阿龍)擁塞控制目的是:限制每個主機的發送的資料量,避免網絡擁塞效率下降。就像廣州等地,限制車牌号出行是一個道理。不然大家都堵在路上,誰都别想走。

擁塞控制的解決方法是流量控制,流量控制的實作是滑動視窗,是以擁塞控制最終也是通過限制發送方的滑動視窗大小來限制流量 。當然,擁塞控制的手段不隻是流量控制,導緻擁塞的因素有:路由器緩存、帶寬、處理器處理速度等等。提升硬體能力(把4車道改成8車道)是其中一個方法,但畢竟硬體提升是有瓶頸的,沒辦法不斷提升,還是需要從tcp本身來增加算法,解決擁塞。

擁塞控制的重點有4個:慢開始、快恢複、快重傳、擁塞避免。這裡依舊獻祭出大學老師的ppt圖檔:

28張圖,Linux netstat指令詳解

Y軸表示的是發送方視窗大小,X軸表示的是發送的輪次(不是位元組編号)。

  • 最開始的時候,會把視窗設定一個較小的值,然後每輪變為原來的兩倍。這是慢開始。
  • 當視窗值到達ssthresh值,這個值是需要通過實時網絡情況設定的一個視窗限制值,開始進入擁塞避免,每輪把視窗值提升1,慢慢試探網絡的底線。
  • 如果發生了資料逾時,表示極可能發生了擁塞,然後回到慢開始,重複上面的步驟。
  • 如果收到三個相同的确認回複,表示現在網絡的情況不太好,把ssthresh的值設定為原來的一半,繼續擁塞避免。這部分稱為快恢複。
  • 如果收到丢包資訊,應該盡快把丢失的包重傳一次,這是快重傳。
  • 當然,視窗的最終上限是不能無限上漲的,他不能超過接收方的緩存區大小。

通過這個算法,就可以在很大程度上,避免網絡擁擠。

除此之外,還可以讓路由器在緩存即将滿的時候,告知發送方我快滿了,而不是等到出現了逾時再進行處理,這是主動隊列管理AQM。此外還有很多方法,但是上面的算法是重點。

/ 面向連接配接 /

這一小節講的就是無人不曉的TCP三向交握與四次揮手這些,經過前面的内容,這一小節其實已經很好了解。

TCP是面向連接配接的,那連接配接是什麼?這裡的連接配接并不是實實在在的連接配接,而是通信雙方彼此之間的一個記錄 。TCP是一個全雙工通信,也就是可以互相發送資料,是以雙方都需要記錄對方的資訊。(阿龍)根據前面的可靠傳輸原理,TCP通信雙方需要為對方準備一個接收緩沖區可以接收對方的資料、記住對方的socket知道怎麼發送資料、記住對方的緩沖區來調整自己的視窗大小等等,這些記錄,就是一個連接配接。

在運輸層小節中講到,運輸層雙方通信的位址是采用socket來定義的,TCP也不例外。TCP的每一個連接配接隻能有兩個對象,也就是兩個socket,而不能有三個。是以socket的定義需要源IP、源端口号、目标IP、目标端口号四個關鍵因素,才不會發生混亂。

假如TCP和UDP一樣隻采用目标IP+目标端口号來定義socket,那麼就會出現多個發送方同時發送到同一個目标socket的情況。這個時候TCP無法區分這些資料是否來自不同的發送方,就會導緻出現錯誤。

既然是連接配接,就有兩個關鍵要點:建立連接配接、斷開連接配接。

建立連接配接

建立連接配接的目的就是交換彼此的資訊,然後記住對方的資訊。是以雙方都需要發送彼此的資訊給對方:

28張圖,Linux netstat指令詳解

但前面的可靠傳輸原理告訴我們,資料在網絡中傳輸是不可靠的,需要對方給予我們一個确認回複,才可以保證消息正确到達。如下圖:

28張圖,Linux netstat指令詳解

機器B的确認收到和機器B資訊可以進行合并,減少次數;而且發送機器B給機器A本身就代表了機器B已經收到了消息,是以最後的示例圖是:

28張圖,Linux netstat指令詳解

步驟如下:

  1. 機器A發送syn包向機器B請求建立TCP連接配接,并附加上自身的接收緩沖區資訊等,機器A進入SYN_SEND狀态,表示請求已經發送正在等待回複;
  2. 機器B收到請求之後,根據機器A的資訊記錄下來,并建立自身的接收緩存區,向機器A發送syn+ack的合成包,同時自身進入SYN_RECV狀态,表示已經準備好了,等待機器A 的回複就可以向A發送資料;
  3. 機器A收到回複之後記錄機器B 的資訊,發送ack資訊,自身進入ESTABLISHED狀态,表示已經完全準備好了,可以進行發送和接收;
  4. 機器B收到ACK資料之後,進入ESTABLISHED狀态。

三次消息的發送,稱為三次握手。

斷開連接配接

斷開連接配接和三次握手類似,直接上圖:

28張圖,Linux netstat指令詳解

1. 機器A發送完資料之後,向機器B請求斷開連接配接,自身進入FIN_WAIT_1狀态,表示資料發送完成且已經發送FIN包(FIN标志位為1);

2. 機器B收到FIN包之後,回複ack包表示已經收到,但此時機器B可能還有資料沒發送完成,(公衆号網絡工程師阿龍)自身進入CLOSE_WAIT狀态,表示對方已發送完成且請求關閉連接配接,自身發送完成之後可以關閉連接配接;

3. 機器B資料發送完成之後,發送FIN包給機器B ,自身進入LAST_ACK狀态,表示等待一個ACK包即可關閉連接配接;

4. 機器A收到FIN包之後,知道機器B也發送完成了,回複一個ACK包,并進入TIME_WAIT狀态

TIME_WAIT狀态比較特殊。當機器A收到機器B的FIN包時,理想狀态下,确實是可以直接關閉連接配接了;但是:

  1. 我們知道網絡是不穩定的,可能機器B 發送了一些資料還沒到達(比FIN包慢);
  2. 同時回複的ACK包可能丢失了,機器B會重傳FIN包;

如果此時機器A馬上關閉連接配接,會導緻資料不完整、機器B無法釋放連接配接等問題。是以此時機器A需要等待2個封包生存最大時長,確定網絡中沒有任何遺留封包了,再關閉連接配接

5. 最後,機器A等待兩個封包存活最大時長之後,機器B 接收到ACK封包之後,均關閉連接配接,進入CLASED狀态

雙方之間4次互相發送封包來斷開連接配接的過程,就是四次揮手。

現在,對于為什麼握手是三次揮手是四次、一定要三次/四次嗎、為什麼要停留2msl再關閉連接配接等等這些問題,就都解決了。

/ UDP協定 /

運輸層協定除了TCP,還有大名鼎鼎的UDP。如果說TCP憑借他完善穩定的功能獨樹一幟,那UDP就是精簡主義亂拳打死老師傅。

UDP隻實作了運輸層最少的功能:程序間通信。對于應用層傳下來的資料,UDP隻是附加一個首部就直接交給網絡層了。UDP的頭部非常簡單,隻有三部分:

  • 源端口、目标端口:端口号用來區分主機的不同程序
  • 校驗碼:用于校驗資料包在傳輸的過程中沒有出現錯誤,例如某個1變成了0
  • 長度:封包的長度

是以UDP的功能也隻有兩個:校驗資料報是否發生錯誤、區分不同的程序通信。

但,TCP的功能雖然多,但同時也是要付出相對應的代價。例如面向連接配接的特性,在建立和斷開連接配接的時候會有開銷;擁塞控制的特性,會限制傳輸的上限等等。下面來羅列一下UDP的優缺點:

UDP的缺點

  • 無法保證消息完整、正确到達,UDP是一個不可靠的傳輸協定;
  • 缺少擁塞控制容易互相競争資源導緻網絡系統癱瘓

UDP的優點

  • 效率更快;不需要建立連接配接以及擁塞控制
  • 連接配接更多的客戶;沒有連接配接狀态,不需要為每個客戶建立緩存等
  • 分組首部位元組少,開銷小;TCP首部固定首部是20位元組,而UDP隻有8位元組;更小的首部意味着更大比例的資料部分
  • 在一些需要高效率允許可限度誤差的場景下可以使用。如直播場景,并不需要保證每個資料包都完整到達,允許一定的丢包率,這個時候TCP的可靠特性反而成為了累贅;精簡的UDP更高的效率是更加适合的選擇
  • 可以進行廣播;UDP并不是面向連接配接的,是以可以同時對多個程序進行發送封包

UDP适用場景

UDP适用于對傳輸模型需要應用層高度自定義、允許出現丢包、需要高效率的場景、需要廣播;例如

  • 視屏直播
  • DNS
  • RIP路由選擇協定

/ 其他補充 /

分塊傳輸

我們可以發現,運輸層在傳輸資料的時候,并不是把整個資料包加個首部直接發送過去,而是會拆分成多個封包分開發送;那他這樣做原因是什麼?

有讀者可能會想到:資料鍊路層限制了資料長度隻能有1460。那資料鍊路層為什麼要這麼限制?他的本質原因就是:網絡是不穩定的。如果封包太長,那麼極有可能在傳輸一般的時候突然中斷了,這個時候就要整個資料重傳,效率就降低了。把資料拆分成多個資料報,那麼當某個資料報丢失,隻需要重傳該資料報即可。

那是不是拆分得越細越好?封包中資料字段長度太低,會使得首部的占比太大,這樣首部就會成為網絡傳輸最大的負擔了。例如1000位元組,每個封包首部是40位元組,如果拆分成10個封包,那麼隻需要傳輸400位元組的首部;而如果拆分成1000個,那麼需要傳輸40000位元組的首部,效率就極大地降低了。

路由轉換

先看下圖:

28張圖,Linux netstat指令詳解
  • 正常情況下,主機A的資料包可以又 1-3-6-7路徑進行傳送
  • 如果路由3壞掉了,那麼可以從 1-4-6-7進行傳送
  • 如果4也壞掉了,那麼隻能從2-5-6-7傳送
  • 如果5壞掉了,那麼就中斷線路了

可以看出來,使用路由轉發的好處是:提高網絡的容錯率,本質原因依舊是網絡是不穩定的 。即使壞掉幾個路由器,網絡依舊暢通。但是如果壞掉路由器6那就直接導緻主機A和主機B無法通信,是以要避免這種核心路由器的存在。

使用路由的好處還有:分流。如果一條線路太擁堵,可以從别的路線進行傳輸,提高效率。

粘包與拆包

在面向位元組流那一小節講過,TCP不懂這些資料流的意義,他隻知道從應用層拿到資料流,切割成一份份封包,然後發送給目标對象。而如果應用層傳輸下來的是兩個資料包,那麼極有可能出現這種情況:

28張圖,Linux netstat指令詳解
  • 應用層需要向目标程序發送兩份資料,一份音頻,一份文本
  • TCP隻知道接收到一個流,并把流拆分成4段進行發送
  • 中間第二個封包的資料就出現兩個檔案的資料混在一起,這就是粘包
  • 目标程序應用層在接收到資料之後,需要把這些資料拆分成正确的兩個檔案,就是拆包

粘包與拆包都是應用層需要解決的問題,可以在每個檔案的最後附加上一些特殊的位元組,如換行符;或者控制每個封包隻包含一個檔案的資料,不足的用0補充等等。

惡意攻擊

TCP的面向連接配接特點可能會被惡意的人利用,對伺服器進行攻擊。

前面我們知道,當我們向一個主機發送syn包請求建立連接配接時,伺服器會為我們建立緩沖區等,然後向我們傳回syn+ack封包;如果我們僞造IP和端口,向一個伺服器進行海量的請求,會使得伺服器建立了大量的建立一半的TCP連接配接,使得其無法正常響應使用者的請求,導緻伺服器癱瘓。

解決的方法可以有限制IP的建立連接配接數、讓建立一半的tcp連接配接在更短的時間内自行關閉、延緩接收緩沖區記憶體的配置設定等等。

長連接配接

我們向伺服器的每一次請求都需要建立一個TCP連接配接,伺服器傳回資料之後就會關閉連接配接;如果在短時間内有大量的請求,那麼頻繁建立TCP連接配接關閉TCP連接配接是一個很浪費資源的行為。是以我們可以讓TCP連接配接不要關閉,在這個期間進行請求,提高效率。

需要注意長連接配接維持時間、建立條件等,避免被惡意利用建立大量的長連接配接,消耗殆盡伺服器的資源。

/ 最後 /

以前學習的時候覺得這些東西好像沒什麼卵用,貌似就是用來考試的。事實上,在沒應用到的時候,對這些知識很難有更深層次的認知,例如現在我看上面的總結,很多隻是表面上的認知,不知道他背後代表的真正含義。

但當我學習的更加廣泛、深入,會對這些知識有越來越深刻的認識。有那麼幾個瞬間覺得:哦原來那個東西是這樣運用,那個東西是這樣的啊,原來學了是真的有用。

現在可能學了之後沒有什麼感覺,但是當用到或者學到相關的應用時,會有一個頓悟感,會瞬間收獲很多。

28張圖,Linux netstat指令詳解
免責聲明:來源https://juejin.cn/post/6932842985616834568,出于傳播學習、交流知識之目的轉載本文,如侵需删,請私信。在此緻謝!

繼續閱讀