當前位置: 妍妍網 > 碼農

透過本文,你可以優雅get到TCP/IP協定精華!

2024-04-28碼農

關註上方 浩道Linux ,回復 資料 ,即可獲取海量 L inux Python 網路通訊、網路安全 等學習資料!

前言

大家好,這裏是 浩道Linux ,主要給大家分享 L inux P ython 網路通訊、網路安全等 相關的IT知識平台。

今天浩道跟大家分享關於TCP/IP協定的硬核幹貨,透過本文,相信你可以很優雅就可以學習到其精華!

本文整理了一些TCP/IP協定簇中需要必知必會的十大問題,既是面試高頻問題,又是IT工程人員必備基礎素養。

TCP/IP十個問題

TCP/IP十個問題

一、TCP/IP模型

TCP/IP協定模型(Transmission Control Protocol/Internet Protocol),包含了一系列構成互聯網基礎的網路協定,是Internet的核心協定。

基於TCP/IP的參考模型將協定分成四個層次,它們分別是鏈路層、網路層、傳輸層和套用層。下圖表示TCP/IP模型與 OSI模型 各層的對照關系。

TCP/IP協定族按照層次由上到下,層層包裝。最上面的是套用層,這裏面有http,ftp,等等我們熟悉的協定。而第二層則是傳輸層,著名的TCP和UDP協定就在這個層次。第三層是網路層,IP協定就在這裏,它負責對數據加上IP地址和其他的數據以確定傳輸的目標。第四層是 數據鏈路層 ,這個層次為待傳送的數據加入一個乙太網路協定頭,並進行 CRC 編碼,為最後的數據傳輸做準備。

上圖清楚地表示了TCP/IP協定中每個層的作用,而TCP/IP協定通訊的過程其實就對應著數據入棧與出棧的過程。入棧的過程,數據發送方每層不斷地封裝首部與尾部,添加一些傳輸的資訊,確保能傳輸到目的地。出棧的過程,數據接收方每層不斷地拆除首部與尾部,得到最終傳輸的數據。

上圖以HTTP協定為例,具體說明。

二、數據鏈路層

實體層負責0、1位元流與物理裝置電壓高低、光的閃滅之間的互換。
數據鏈路層負責將0、1序列劃分為數據幀從一個節點傳輸到臨近的另一個節點,這些節點是透過MAC來唯一標識的(MAC,實體位址,一個主機會有一個MAC地址)。

  • 封裝成幀: 把網路層數據報加頭和尾,封裝成幀,幀頭中包括源MAC地址和目的MAC地址。

  • 透明傳輸 :零位元填充、轉義字元。

  • 可靠傳輸: 在出錯率很低的鏈路上很少用,但是無線鏈路WLAN會保證可靠傳輸。

  • 差錯檢測(CRC):接收者檢測錯誤,如果發現差錯,丟棄該幀。

  • 三、網路層

    1.IP協定

    IP協定是TCP/IP協定的核心,所有的TCP,UDP, IMCP ,IGMP的數據都以IP數據格式傳輸。要註意的是,IP不是可靠的協定,這是說,IP協定沒有提供一種數據未傳達以後的處理機制,這被認為是上層協定:TCP或UDP要做的事情。

    1.1 IP地址

    在數據鏈路層中我們一般透過MAC地址來辨識不同的節點,而在IP層我們也要有一個類似的地址標識,這就是IP地址。

    32位元IP地址分為網路位和地址位,這樣做可以減少路由器中路由表記錄的數目,有了網路地址,就可以限定擁有相同網路地址的終端都在同一個範圍內,那麽路由表只需要維護一條這個網路地址的方向,就可以找到相應的這些終端了。

    AIP地址: 0.0.0.0~127.0.0.0
    BIP地址:128.0.0.1~191.255.0.0
    CIP地址:192.168.0.0~239.255.255.0

    1.2 IP協定頭

    這裏只介紹:八位的TTL欄位。這個欄位規定該封包在穿過多少個路由之後才會被拋棄。某個IP封包每穿過一個路由器,該封包的TTL數值就會減少1,當該封包的TTL成為零,它就會被自動拋棄。

    這個欄位的最大值也就是255,也就是說一個協定包也就在路由器裏面穿行255次就會被拋棄了,根據系統的不同,這個數位也不一樣,一般是32或者是64。

    2.ARP及RARP協定

    ARP 是根據IP地址獲取MAC地址的一種協定。

    ARP(地址解析)協定是一種解析協定,本來主機是完全不知道這個IP對應的是哪個主機的哪個介面,當主機要發送一個IP包的時候,會首先查一下自己的ARP快取(就是一個IP-
    MAC地址對應表緩存)。

    如果查詢的IP-MAC值對不存在,那麽主機就向網路發送一個ARP協定廣播包,這個廣播包裏面就有待查詢的IP地址,而直接收到這份廣播的包的所有主機都會查詢自己的IP地址,如果收到廣播包的某一個主機發現自己符合條件,那麽就準備好一個包含自己的MAC地址的ARP包傳送給發送ARP廣播的主機。

    而廣播主機拿到ARP包後會更新自己的ARP緩存(就是存放IP-
    MAC對應表的地方)。發送廣播的主機就會用新的ARP緩存數據準備好數據鏈路層的的封包發送工作。

    RARP協定的工作與此相反,不做贅述。

    3. ICMP協定

    IP協定並不是一個可靠的協定,它不保證數據被送達,那麽,自然的,保證數據送達的工作應該由其他的模組來完成。其中一個重要的模組就是ICMP(網路控制報文)協定。ICMP不是高層協定,而是IP層的協定。

    當傳送IP封包發生錯誤。比如主機不可達,路由不可達等等,ICMP協定將會把錯誤資訊封包,然後傳送回給主機。給主機一個處理錯誤的機會,這
    也就是為什麽說建立在IP層以上的協定是可能做到安全的原因。

    四、ping

    ping可以說是ICMP的最著名的套用,是TCP/IP協定的一部份。利用「ping」命令可以檢查網路是否連通,可以很好地幫助我們分析和判定網路故障。

    例如:當我們某一個網站上不去的時候。通常會ping一下這個網站。ping會回顯出一些有用的資訊。一般的資訊如下:

    ping這個單詞源自聲納定位,而這個程式的作用也確實如此,它利用ICMP協定包來偵測另一個主機是否可達。原理是用型別碼為0的ICMP發請

    求,受到請求的主機則用型別碼為8的ICMP回應。

    ping程式來計算間隔時間,並計算有多少個包被送達。使用者就可以判斷網路大致的情況。我們可以看到, ping給出來了傳送的時間和TTL的數據。

    五、Traceroute

    Traceroute是用來偵測主機到目的主機之間所經路由情況的重要工具,也是最便利的工具。

    Traceroute的原理是非常非常的有意思,它收到到目的主機的IP後,首先給目的主機發送一個TTL=1的UDP封包,而經過的第一個路由器收到這個封包以後,就自動把TTL減1,而TTL變為0以後,路由器就把這個包給拋棄了,並同時產生
    一個主機不可達的ICMP數據報給主機。主機收到這個數據報以後再發一個TTL=2的UDP數據報給目的主機,然後刺激第二個路由器給主機發ICMP數據報。如此往復直到到達目的主機。這樣,traceroute就拿到了所有的路由器IP。

    六、TCP/UDP

    TCP/UDP都是是傳輸層協定,但是兩者具有不同的特性,同時也具有不同的套用場景,下面以圖表的形式對比分析。

    面向報文

    面向報文的傳輸方式是套用層交給UDP多長的報文,UDP就照樣發送,即一次發送一個報文。因此,應用程式必須選擇合適大小的報文。若報文太長,則IP層需要分片,降低效率。若太短,會是IP太小。

    面向字節流

    面向字節流的話,雖然應用程式和TCP的互動是一次一個數據塊(大小不等),但TCP把應用程式看成是一連串的無結構的字節流。TCP有一個緩沖,當應用程式傳送的數據塊太長,TCP就可以把它劃分短一些再傳送。

    關於擁塞控制,流量控制,是TCP的重點,後面講解。

    TCP和UDP協定的一些套用

    什麽時候應該使用TCP?

    當對網路通訊品質有要求的時候,比如:整個數據要準確無誤的傳遞給對方,這往往用於一些要求可靠的套用,比如HTTP、HTTPS、FTP等傳輸檔的協定,POP、SMTP等信件傳輸的協定。

    什麽時候應該使用UDP?

    當對網路通訊品質要求不高的時候,要求網路通訊速度能盡量的快,這時就可以使用UDP。

    七、DNS

    DNS(Domain Name
    System,網域名稱系統),因特網上作為網域名稱和IP地址相互對映的一個分布式資料庫,能夠使使用者更方便的存取互聯網,而不用去記住能夠被機器直接讀取的IP數串。透過主機名,最終得到該主機名對應的IP地址的過程叫做網域名稱解析(或主機名解析)。DNS協定執行在UDP協定之上,使用埠號53。

    八、TCP連線的建立與終止

    1.三次握手

    TCP是面向連線的,無論哪一方向另一方發送數據之前,都必須先在雙方之間建立一條連線。在TCP/IP協定中,TCP協定提供可靠的連線服務,連線是透過三次握手進行初始化的。三次握手的目的是同步連線雙方的序列號和確認號並交換
    TCP視窗大小資訊。

    第一次握手: 建立連線。客戶端發送連線請求報文段,將SYN位置為1,Sequence
    Number為x;然後,客戶端進入SYN_SEND狀態,等待伺服器的確認;

    第二次握手: 伺服器收到SYN報文段。伺服器收到客戶端的SYN報文段,需要對這個SYN報文段進行確認,設定Acknowledgment Number為x+1(Sequence Number+1);同時,自己自己還要發送SYN請求資訊,將SYN位置為1,Sequence
    Number為y;伺服器端將上述所有資訊放到一個報文段(即SYN+ACK報文段)中,一並行送給客戶端,此時伺服器進入SYN_RECV狀態;

    第三次握手: 客戶端收到伺服器的SYN+ACK報文段。然後將Acknowledgment
    Number設定為y+1,向伺服器發送ACK報文段,這個報文段發送完畢以後,客戶端和伺服器端都進入ESTABLISHED狀態,完成TCP三次握手。

    為什麽要三次握手?

    為了防止已失效的連線請求報文段突然又傳送到了伺服端,因而產生錯誤。

    具體例子:「已失效的連線請求報文段」的產生在這樣一種情況下:client發出的第一個連線請求報文段並沒有遺失,而是在某個網路結點長時間的滯留了,以致延誤到連線釋放以後的某個時間才到達server。本來這是一個早已失效的報文段。但server收到此失效的連線請求報文段後,就誤認為是client再次發出的一個新的連線請求。於是就向client發出確認報文段,同意建立連線。假設不采用「三次握手」,那麽只要server發出確認,新的連線就建立了。由於現在client並沒有發出建立連線的請求,因此不會理睬server的確認,也不會向server發送數據。但server卻以為新的運輸連線已經建立,並一直等待client發來數據。這樣,server的很多資源就白白浪費掉了。采用「三次握手」的辦法可以防止上述現象發生。例如剛才那種情況,client不會向server的確認發出確認。server由於收不到確認,就知道client並沒有要求建立連線。」

    2.四次揮手

    當客戶端和伺服器透過三次握手建立了TCP連線以後,當數據傳送完畢,肯定是要斷開TCP連線的啊。那對於TCP的斷開連線,這裏就有了神秘的「四次分手」。

    第一次分手: 主機1(可以 客戶端,也可以是伺服器端),設定Sequence
    Number,向主機2發送一個FIN報文段;此時,主機1進入FIN_WAIT_1狀態;這表示主機1沒有數據要發送給主機2了;

    第二次分手: 主機2收到了主機1發送的FIN報文段,向主機1回一個ACK報文段,Acknowledgment Number為Sequence Number加1;主機1進入FIN_WAIT_2狀態;主機2告訴主機1,我「同意」你的關閉請求;

    第三次分手: 主機2向主機1發送FIN報文段,請求關閉連線,同時主機2進入LAST_ACK狀態;

    第四次分手: 主機1收到主機2發送的FIN報文段,向主機2發送ACK報文段,然後主機1進入TIME_WAIT狀態;主機2收到主機1的ACK報文段以後,就關閉連線;此時,主機1等待2MSL後依然沒有收到回復,則證明Server端已正常關閉,那好,主機1也可以關閉連線了。

    為什麽要四次分手?

    TCP協定是一種面向連線的、可靠的、基於字節流的運輸層通訊協定。TCP是全雙工模式,這就意味著,當主機1發出FIN報文段時,只是表示主機1已經沒有數據要發送了,主機1告訴主機2,它的數據已經全部發送完畢了;但是,這個時候主機1還是可以接受來自主機2的數據;當主機2返回ACK報文段時,表示它已經知道主機1沒有數據發送了,但是主機2還是可以發送數據到主機1的;當主機2也發送了FIN報文段時,這個時候就表示主機2也沒有數據要發送了,就會告訴主機1,我也沒有數據要發送了,之後彼此就會愉快的中斷這次TCP連線。

    為什麽要等待2MSL?

    MSL:報文段最大生存時間,它是任何報文段被丟棄前在網路內的最長時間。
    原因有二:

  • 保證TCP協定的全雙工連線能夠可靠關閉

  • 保證這次連線的重復數據段從網路中消失

  • 第一點:如果主機1直接CLOSED了,那麽由於IP協定的不可靠性或者是其它網路原因,導致主機2沒有收到主機1最後回復的ACK。那麽主機2就會在超時之後繼續發送FIN,此時由於主機1已經CLOSED了,就找不到與重發的FIN對應的連線。所以,主機1不是直接進入CLOSED,而是要保持TIME_WAIT,當再次收到FIN的時候,能夠保證對方收到ACK,最後正確的關閉連線。

    第二點:如果主機1直接CLOSED,然後又再向主機2發起一個新連線,我們不能保證這個新連線與剛關閉的連線的埠號是不同的。也就是說有可能新連線和老連線的埠號是相同的。一般來說不會發生什麽問題,但是還是有特殊情況出現:假設新連線和已經關閉的老連線埠號是一樣的,如果前一次連線的某些數據仍然滯留在網路中,這些延遲數據在建立新連線之後才到達主機2,由於新連線和老連線的埠號是一樣的,TCP協定就認為那個延遲的數據是屬於新連線的,這樣就和真正的新連線的封包發生混淆了。所以TCP連線還要在TIME_WAIT狀態等待2倍MSL,這樣可以保證本次連線的所有數據都從網路中消失。

    九、TCP流量控制

    如果發送方把數據發送得過快,接收方可能會來不及接收,這就會造成數據的遺失。所謂 流量控制 就是讓發送方的發送速率不要太快,要讓接收方來得及接收。

    利用 滑動視窗機制 可以很方便地在TCP連線上實作對發送方的流量控制。

    設A向B發送數據。在連線建立時,B告訴了A:「我的接收視窗是 rwnd = 400 」(這裏的 rwnd 表示 receiver window)
    。因此,發送方的發送視窗不能超過接收方給出的接收視窗的數值。請註意,TCP的視窗單位是字節,不是報文段。假設每一個報文段為100字節長,而資料包段序號的初始值設為1。大寫ACK表示首部中的確認位ACK,小寫ack表示確認欄位的值ack。

    從圖中可以看出,B進行了三次流量控制。第一次把視窗減少到 rwnd = 300 ,第二次又減到了 rwnd = 100 ,最後減到 rwnd = 0,即不允許發送方再發送數據了。這種使發送方暫停發送的狀態將持續到主機B重新發出一個新的視窗值為止。B向A發送的三個報文段都設定了 ACK = 1,只有在ACK=1時確認號欄位才有意義。

    TCP為每一個連線設有一個持續計時器(persistence timer)。只要TCP連線的一方收到對方的零視窗通知,就啟動持續計時器。若持續計時器設定的時間到期,就發送一個零視窗控測報文段(攜1字節的數據),那麽收到這個報文段的一方就重新設定持續計時器。

    十、TCP擁塞控制

    1.慢開始和擁塞避免

    發送方維持一個擁塞視窗 cwnd ( congestion window
    )的狀態變量。擁塞視窗的大小取決於網路的擁塞程度,並且動態地在變化。發送方讓自己的發送視窗等於擁塞視窗。

    發送方控制擁塞視窗的原則是:只要網路沒有出現擁塞,擁塞視窗就再增大一些,以便把更多的分組發送出去。但只要網路出現擁塞,擁塞視窗就減小一些,以減少註入到網路中的分組數。

    慢開始演算法:

    當主機開始發送數據時,如果立即所大量數據字節註入到網路,那麽就有可能引起網路擁塞,因為現在並不清楚網路的負荷情況。
    因此,較好的方法是 先探測一下,即由小到大逐漸增大發送視窗,也就是說,由小到大逐漸增大擁塞視窗數值。

    通常在剛剛開始發送報文段時,先把擁塞視窗 cwnd
    設定為一個最大報文段MSS的數值。而在每收到一個對新的報文段的確認後,把擁塞視窗增加至多一個MSS的數值。用這樣的方法逐步增大發送方的擁塞視窗 cwnd
    ,可以使分組註入到網路的速率更加合理。

    每經過一個傳輸輪次,擁塞視窗 cwnd 就加倍。 一個傳輸輪次所經歷的時間其實就是往返時間RTT。

    不過「傳輸輪次」更加強調:把擁塞視窗cwnd所允許發送的報文段都連續發送出去,並收到了對已發送的最後一個字節的確認。

    另,慢開始的「慢」並不是指cwnd的增長速率慢,而是指在TCP開始發送報文段時先設定cwnd=1,使得發送方在開始時只發送一個報文段(目的是試探一下網路的擁塞情況),然後再逐漸增大cwnd。

    為了防止擁塞視窗cwnd增長過大引起網路擁塞,還需要設定一個慢開始門限ssthresh狀態變量。慢開始門限ssthresh的用法如下:

  • 當 cwnd < ssthresh 時,使用上述的慢開始演算法。

  • 當 cwnd > ssthresh 時,停止使用慢開始演算法而改用擁塞避免演算法。

  • 當 cwnd = ssthresh 時,既可使用慢開始演算法,也可使用擁塞控制避免演算法。

  • 擁塞避免

    讓擁塞視窗cwnd緩慢地增大,即每經過 一個往返時間RTT 就把發送方的 擁塞視窗cwnd加1,而不是加倍
    。這樣擁塞視窗cwnd按線性規律緩慢增長,比慢開始演算法的擁塞視窗增長速率緩慢得多。

    無論在慢開始階段還是在擁塞避免階段,只要發送方判斷網路出現擁塞(其根據就是沒有收到確認),就要把慢開始門限ssthresh設定為出現擁塞時的發送
    方視窗值的一半(但不能小於2)。然後把擁塞視窗cwnd重新設定為1,執行慢開始演算法。

    這樣做的目的就是要迅速減少主機發送到網路中的分組數,使得發生 擁塞的路由器有足夠時間把佇列中積壓的分組處理完畢。

    如下圖,用具體數值說明了上述擁塞控制的過程。現在發送視窗的大小和擁塞視窗一樣大。

    2.快重傳和快恢復

    快重傳

    快重傳演算法首先要求接收方每收到一個失序的報文段後就立即發出重復確認(為的是使發送方及早知道有報文段沒有到達對方)而不要等到自己發送數據時才進行捎帶確認。

    接收方收到了M1和M2後都分別發出了確認。現在假定接收方沒有收到M3但接著收到了M4。

    顯然,接收方不能確認M4,因為M4是收到的失序報文段。根據 可靠傳輸原理,接收方可以什麽都不做,也可以在適當時機發送一次對M2的確認。

    但按照快重傳演算法的規定,接收方應及時發送對M2的重復確認,這樣做可以讓
    發送方及早知道報文段M3沒有到達接收方。發送方接著發送了M5和M6。接收方收到這兩個報文後,也還要再次發出對M2的重復確認。這樣,發送方共收到了
    接收方的四個對M2的確認,其中後三個都是重復確認。

    快重傳演算法還規定,發送方只要一連收到三個重復確認就應當立即重傳對方尚未收到的報文段M3,而不必 繼續等待M3設定的重傳計時器到期。

    由於發送方盡早重傳未被確認的報文段,因此采用快重傳後可以使整個網路吞吐量提高約20%。

    快恢復

    與快重傳配合使用的還有快恢復演算法,其過程有以下兩個要點:

  • 當發送方連續收到三個重復確認,就執行「乘法減小」演算法,把慢開始門限ssthresh減半。

  • 與慢開始不同之處是現在不執行慢開始演算法(即擁塞視窗cwnd現在不設定為1),而是把cwnd值設定為 慢開始門限ssthresh減半後的數值,然後開始執行擁塞避免演算法(「加法增大」),使擁塞視窗緩慢地線性增大。

  • 更多精彩

    關註公眾號 浩道Linux

    浩道Linux ,專註於 Linux系統 的相關知識、 網路通訊 網路安全 Python相關 知識以及涵蓋IT行業相關技能的學習, 理論與實戰結合,真正讓你在學習工作中真正去用到所學。同時也會分享一些面試經驗,助你找到高薪offer,讓我們一起去學習,一起去進步,一起去漲薪!期待您的加入~~~ 關註回復「資料」可 免費獲取學習資料 (含有電子書籍、視訊等)。

    喜歡的話,記得 點「贊」 「在看」