<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          一個 HTTP 請求的曲折經(jīng)歷

          共 11618字,需瀏覽 24分鐘

           ·

          2020-06-28 23:22

          點擊關(guān)注上方“杰哥的IT之旅”,后臺回復(fù)“Python自動化”獲取精心整理的PDF。

          
           

          來源:8rr.co/6usv


          從一個經(jīng)典的面試題說起,輸入URL到頁面展現(xiàn)的過程: 

          1. 輸入URL后,會先進(jìn)行域名解析。優(yōu)先查找本地host文件有無對應(yīng)的IP地址,沒有的話去本地DNS服務(wù)器查找,還不行的話,本地DNS服務(wù)器會去找根DNS服務(wù)器要一個域服務(wù)器的地址進(jìn)行查詢,域服務(wù)器將要查詢的域名的解析服務(wù)器地址返回給本地DNS,本地DNS去這里查詢就OK了。
          2. 瀏覽器拿到服務(wù)器的IP地址后,會向它發(fā)送HTTP請求。HTTP請求經(jīng)由一層層的處理、封裝、發(fā)出之后,最終經(jīng)由網(wǎng)絡(luò)到達(dá)服務(wù)器,建立TCP/IP連接,服務(wù)器接收到請求并開始處理。
          3. 服務(wù)器構(gòu)建響應(yīng),再經(jīng)由一層層的處理、封裝、發(fā)出后,到達(dá)客戶端,瀏覽器處理請求。
          4. 瀏覽器開始渲染頁面,解析HTML,構(gòu)建render樹,根據(jù)render樹的節(jié)點和CSS的對應(yīng)關(guān)系,進(jìn)行布局,繪制頁面。

          這4個步驟包含了一個HTTP請求的完整生命周期,文章著重介紹第2步和第3步,也就是請求是如何在兩個物理端點之間進(jìn)行通信的。數(shù)據(jù)的發(fā)出和接收必然會經(jīng)歷一些處理、解析的過程,這些過程在系統(tǒng)的不同層次進(jìn)行。

          分層

          一個HTTP請求從源端發(fā)出到在終端接收的處理過程都是要經(jīng)過以下四層。其中每一層都有各自的協(xié)議。e435b229743fa5d42ce602d0014a853d.webp

          我們先來理解一下協(xié)議是什么,協(xié)議是經(jīng)過約定,雙方共同承認(rèn),并且需要共同遵守的規(guī)則。上面的每一層,都有各自的協(xié)議,協(xié)議的執(zhí)行者是通信鏈路兩端內(nèi)的對應(yīng)層。每一層通過協(xié)議來理解數(shù)據(jù),并進(jìn)行處理。

          上圖中只舉例出了最常見的協(xié)議,實際上每一層都有細(xì)分的協(xié)議:

          • 應(yīng)用層:應(yīng)用程序負(fù)責(zé)將數(shù)據(jù)以相應(yīng)規(guī)則(協(xié)議)進(jìn)行包裝,發(fā)給傳輸層
            • HTTP:超文本傳輸協(xié)議
            • FTP:文件傳輸協(xié)議
            • SMTP:簡單郵件傳送協(xié)議
            • SNMP:簡單網(wǎng)絡(luò)管理協(xié)議
          • 傳輸層:負(fù)責(zé)將應(yīng)用層傳過來的數(shù)據(jù)進(jìn)行分組,為確保終端接收數(shù)據(jù)的順序和完整性,會對每個分組進(jìn)行標(biāo)記,交給網(wǎng)絡(luò)層
            • TCP:傳輸控制協(xié)議
            • UDP:用戶數(shù)據(jù)協(xié)議
          • 網(wǎng)絡(luò)層:負(fù)責(zé)將傳輸層發(fā)來的數(shù)據(jù)分組發(fā)送到目標(biāo)終端
            • IP:網(wǎng)際協(xié)議
            • ICMP:Internet互聯(lián)網(wǎng)控制報文協(xié)議
            • IGMP:Internet組管理協(xié)議
          • 鏈路層:為網(wǎng)絡(luò)層發(fā)送和接收數(shù)據(jù)單元
            • ARP:地址解析協(xié)議
            • RARP:逆地址解析協(xié)議

          封裝和分用

          數(shù)據(jù)在經(jīng)過每一層的時候都要被對應(yīng)的協(xié)議包裝,到達(dá)終端的時候,要一層一層的解包。這兩個過程叫封裝和分用。

          發(fā)送時,用戶數(shù)據(jù)被HTTP封裝為報文,每一層會將上層傳過來的報文作為本層的數(shù)據(jù)塊,并添加自己的首部,其中包含了協(xié)議標(biāo)識,這一整體作為本層報文向下傳遞。

          接收時,數(shù)據(jù)自下而上流動,經(jīng)過每一層時被去掉報文首部,根據(jù)報文標(biāo)識確定正確的上層協(xié)議,最終到應(yīng)用層被應(yīng)用程序處理。

          封裝

          源端發(fā)送HTTP報文時,報文會以數(shù)據(jù)流的形式通過一條已經(jīng)打開的TCP連接按序傳輸,TCP收到數(shù)據(jù)流后會將其分割成小的數(shù)據(jù)塊,每個小塊被添加的TCP首部與數(shù)據(jù)塊共同組成了TCP分組,分組經(jīng)由網(wǎng)絡(luò)層發(fā)送,網(wǎng)絡(luò)層遵循IP協(xié)議,當(dāng)收到分組發(fā)送請求后,會將分組其放入IP數(shù)據(jù)報,填充報頭,將數(shù)據(jù)報發(fā)經(jīng)由鏈路層發(fā)送出去。

          f1d73eaad6052dda3dcfc65127220f84.webp

          這一過程經(jīng)過每層的時候都會被增加一些首部信息,有時還需要增加尾部信息,每一層都會把數(shù)據(jù)封裝到各自的報文中, 并在報文首部添加協(xié)議標(biāo)識,這個過程叫封裝。

          分用

          終端接收到一個以太網(wǎng)數(shù)據(jù)幀時,數(shù)據(jù)自底層向上流動,去掉發(fā)送時各層協(xié)議加上的報文首部,每層協(xié)議都要檢查報文首部的協(xié)議標(biāo)識,從而確定上層協(xié)議,保證數(shù)據(jù)被正確處理,這個過程叫分用。

          28178b36d1e14da191cad4e6dd288bda.webp

          終端從鏈路層接收到數(shù)據(jù)請求后,進(jìn)入網(wǎng)絡(luò)層對數(shù)據(jù)進(jìn)行解析,交給給傳輸層,校驗分組順序和完整性,從數(shù)據(jù)塊中取出數(shù)據(jù),得到HTTP報文,交給應(yīng)用層進(jìn)行處理。這個過程會逐層剝離報頭還原數(shù)據(jù)。

          逐層分析

          我們已經(jīng)知道,數(shù)據(jù)是從源端自上而下到終端自下而上被一層層處理的,現(xiàn)在就來看一下每層都做了什么事情。

          HTTP

          HTTP屬于應(yīng)用層,用戶觸發(fā)交互所產(chǎn)生的行為數(shù)據(jù)和服務(wù)端對此的響應(yīng)都由它封裝成HTTP報文,再交由下層協(xié)議進(jìn)行處理。報文的作用是客戶端與服務(wù)端溝通的載體,雙方都要遵循統(tǒng)一規(guī)則對信息進(jìn)行處理,這一規(guī)則稱為HTTP。

          客戶端與服務(wù)端的交互往往非常復(fù)雜,為了使雙方都能高效、明確、安全地通信(例如傳遞意圖與狀態(tài)、承載數(shù)據(jù)、攜帶認(rèn)證信息、控制連接行為與緩存),需要依賴報文中的結(jié)構(gòu)來實現(xiàn),下面先從結(jié)構(gòu)開始看。

          報文結(jié)構(gòu)

          HTTP報文的結(jié)構(gòu)分為請求和響應(yīng)兩種,請求報文封裝用戶操作產(chǎn)生的動作,告知服務(wù)器應(yīng)采取什么行為,響應(yīng)報文來告知客戶端請求的結(jié)果。

          請求報文格式:

          
              
               
               
                 // 起始行格式
                
          // 首部
          // 實體

          響應(yīng)報文格式:

          
              
               
               
                 // 起始行格式
                
          // 首部
          // 實體

          起始行

          報文的起始行表明了報文的開始,請求和響應(yīng)各自的起始行的格式也不相同。

          請求報文的起始行說明要做什么,結(jié)構(gòu)為方法 + 請求URL + 協(xié)議版本,中間用空格做分隔:

          GET /api/nht/blog/example HTTP/1.1

          響應(yīng)報頭的起始行說明發(fā)生了什么,結(jié)構(gòu)為協(xié)議版本 + 狀態(tài)碼 + 描述文本,中間用空格做分隔:

          HTTP/1.1 200 OK

          方法與狀態(tài)碼

          方法來告訴服務(wù)端請求報文要做的事情,狀態(tài)碼來通知客戶端服務(wù)端依據(jù)請求報文完成動作之后的大致結(jié)果。常見的HTTP方法如下:

          方法 含義 有無主體
          GET 從服務(wù)端獲取資源
          HEAD 只獲取資源頭部
          POST 向服務(wù)端發(fā)送數(shù)據(jù)
          PUT 將客戶端發(fā)送的數(shù)據(jù)存到服務(wù)端,應(yīng)用場景多為修改
          OPTIONS 對服務(wù)端進(jìn)行預(yù)檢,例如服務(wù)端支持哪些方法
          DELETE 從服務(wù)端刪除資源

          請求完成時,響應(yīng)報文中會有一個狀態(tài)碼,用來表示此次請求的狀態(tài),是成功了還是失敗了,或者時需要重定向。狀態(tài)碼的范圍從100到599, 其中有部分是已經(jīng)定義的。不同的范圍表示的含義也不同:

          范圍 已定義范圍 含義
          100~199 100~101 信息提示
          200~299 200~206 成功
          300~399 300~305 重定向
          400~499 400~415 客戶端錯誤
          500~599 500~505 服務(wù)端錯誤

          首部

          首部是請求和響應(yīng)報文中的一些信息,形式為鍵值對,每對鍵值結(jié)尾是CRLF換行符,它決定了請求或者響應(yīng)報文的屬性,比如Content-Type表明了請求主體的數(shù)據(jù)類型,Date說明了請求的創(chuàng)建時間。客戶端與服務(wù)端通過首部來協(xié)商具體行為。可以根據(jù)請求、響應(yīng)、結(jié)構(gòu)等,將首部分為五種。

          • 請求首部:是放在請求報文中的首部,它被用來告訴服務(wù)端一些信息。
          • 響應(yīng)首部:為客戶端提供一些可能用到的信息。
          • 通用首部:請求與響應(yīng)報文都包含的首部,例如Date首部
          • 實體首部:對于報文實體主體部分的描述,比如Content-Type,表明其數(shù)據(jù)類型。
          • 擴(kuò)展首部:開發(fā)者自己添加的首部字段,用來滿足定制化需求。

          實體

          HTTP/1.0 200 OK
          Server: xxxxxxx
          Date: Sun,17 Sep 2019 02:01:16 GMT
          --------------------------------實體首部
          Content-Type: text/plain
          Content-length: 18
          --------------------------------實體主體

          Hi! I"m a message!
          --------------------------------

          實體部分是可選的,它被用來運送請求或者響應(yīng)的數(shù)據(jù),實體由實體首部 + 實體主體組成,實體首部對實體主體做描述。HTTP/1.1定義了以下的基本實體首部字段:

          • Content-Type: 實體主體中的數(shù)據(jù)類型。
          • Content-Length: 實體主體的長度或者大小。
          • Content-Language: 和傳輸?shù)臄?shù)據(jù)最匹配的語言。
          • Content-Encoding: 來標(biāo)識服務(wù)端編碼時所用的編碼方式。
          • Content-Location: 要返回的數(shù)據(jù)的地址。
          • Content-Range: 如果是部分實體,用來標(biāo)記它是實體的哪個部分。
          • Content-MD5: 實體主體內(nèi)容的校驗和。
          • Last-Modified: 所傳輸內(nèi)容在服務(wù)器上創(chuàng)建或者最后修改的日期時間。
          • Expires: 實體數(shù)據(jù)試下的日期時間。
          • Allow: 所請求資源允許的請求方法。
          • ETag: 資源的特定版本的標(biāo)識符。可以讓緩存更高效,并節(jié)省帶寬。
          • Cache-Control: 控制緩存機(jī)制的指令。

          以上是HTTP報文包含的主要結(jié)構(gòu),當(dāng)請求報文到達(dá)服務(wù)器時,服務(wù)器會對報文中的內(nèi)容解析出來,根據(jù)方法、資源路徑、首部、和主體來處理請求,然后通過對請求資源的訪問結(jié)果,來構(gòu)建響應(yīng),回送給客戶端。

          傳輸層-TCP

          HTTP連接是建立在TCP連接的基礎(chǔ)之上的,TCP提供可靠的數(shù)據(jù)連接。當(dāng)要傳輸一個HTTP報文時,報文數(shù)據(jù)會以流的形式通過一條已經(jīng)打開的TCP連接按順序傳輸,TCP會將收到的數(shù)據(jù)分成小塊,每塊是一個TCP分組。

          由于數(shù)據(jù)是分成小塊發(fā)送的,所以完整可靠的數(shù)據(jù)傳輸主要體現(xiàn)在:分組是否完整、分組順序是否正常、分組是否損壞、分組數(shù)據(jù)是否重復(fù)。這些可以通過TCP的檢驗和、序列號、確認(rèn)應(yīng)答、重發(fā)控制、連接管理和窗口機(jī)制來控制。

          TCP是傳輸控制協(xié)議,傳輸控制主要依賴首部包含的6個標(biāo)志,它們控制報文的傳輸狀態(tài),以及發(fā)送端和接收端應(yīng)對數(shù)據(jù)采取的動作。當(dāng)它們的值為1時,標(biāo)志對應(yīng)的各自功能才允許被執(zhí)行,比如當(dāng)URG為1時,報文首部的緊急指針部分才有效。

          • URG 緊急指針
          • ACK 確認(rèn)序號有效
          • PSH 接收方應(yīng)該盡快將這個報文段交給應(yīng)用層。
          • RST 重建連接
          • SYN 同步序號用來發(fā)起一個連接
          • FIN 發(fā)端完成發(fā)送任務(wù)
          f50be7794b22655bbbe4241b52885cb7.webp

          源端口和目的端口:標(biāo)識發(fā)送方和接收方的端口號,一個TCP連接通過4個值確認(rèn):源IP、源端口、目的IP、目的端口,其中源IP和目的IP包含在IP分組內(nèi)。

          首部長度:表示TCP首部的字節(jié)長度,也能標(biāo)記出從多少個字節(jié)開始,才是需要傳輸?shù)臄?shù)據(jù)。

          TCP段序號:本段報文發(fā)送的數(shù)據(jù)第一個字節(jié)的序號,每段報文中的數(shù)據(jù)的每個字節(jié)都有序號,第一個字節(jié)的序號從0開始,依次加1,加到2的32次方減1后再次從0開始。

          TCP段確認(rèn)序號 :當(dāng)首部標(biāo)志ACK為1時,確認(rèn)序號有效。TCP段被接收端接收后,會回送給發(fā)送端一個確認(rèn)號,為上次接受的最后一個字節(jié)序號加1。

          檢驗和:由發(fā)送端計算,接收端驗證,如果接收方檢測到檢驗和不正確,表明該TCP段可能有損壞,會被丟棄,同時接收端向回送一個重復(fù)的確認(rèn)號(與最近的一次正確的報文傳輸?shù)拇_認(rèn)號重復(fù)),表明接收到的TCP段是錯誤的,并告知自己希望收到的序號。這時發(fā)送端需要立即重傳出錯的TCP段。

          緊急指針:當(dāng)首部標(biāo)志URG為1時,緊急指針有效,表示發(fā)送端向接收端要發(fā)送緊急數(shù)據(jù)。緊急指針是一個正偏移量,它和TCP段序號相加,計算出緊急數(shù)據(jù)的最后一個字節(jié)的序號。比如接收方接收到數(shù)據(jù),從序號為1000的字節(jié)開始讀取,緊急指針為1000,那么緊急數(shù)據(jù)就是序號從1000到2000之間的字節(jié)。這些數(shù)據(jù)由接收方?jīng)Q定如何處理。

          窗口尺寸:決定了TCP一次成塊數(shù)據(jù)流的吞吐量。需要注意的是,它表示的是發(fā)送一方的允許對方發(fā)送的數(shù)據(jù)量,比如發(fā)送方首部中的窗口大小為1000,就表示發(fā)送方最多可以接受對方發(fā)來的1000個字節(jié)的數(shù)據(jù)量。這與發(fā)送方的數(shù)據(jù)緩存空間有關(guān),會影響TCP的性能。

          首部標(biāo)志PSH:如果需要告訴接收方將數(shù)據(jù)立即全部提交給接收進(jìn)程,發(fā)送方需要將PSH置為1,這里的數(shù)據(jù)是和PSH一起傳送的數(shù)據(jù)以及之前接收到的全部數(shù)據(jù)。如果接收方收到了PSH為1的標(biāo)志,需要立即將數(shù)據(jù)提交給接收進(jìn)程,不用再等待有沒有其他數(shù)據(jù)進(jìn)來。

          復(fù)位標(biāo)志RST:當(dāng)RST為1時,表示連接出現(xiàn)了異常情況,接收方將終止連接,通知應(yīng)用層重新建立連接。

          同步序號SYN:用來建立連接,涉及到TCP的三次握手。

          1. 開始建立連接時,客戶端向服務(wù)器發(fā)送一個TCP分組,分組首部的SYN為1,并攜帶一個初始序號,表明這是一個連接請求。
          2. 如果服務(wù)器接受了連接,會向客戶端發(fā)送一個TCP分組,分組中會包含SYN和ACK,都為1,同時包含一個確認(rèn)序號,值為來自客戶端的初始序號 + 1,表示連接已經(jīng)被接受。
          3. 客戶端收到上一步發(fā)來的分組后,會再向服務(wù)器發(fā)送一段確認(rèn)報文分組,ACK為1,會再次攜帶確認(rèn)序號,值是第二步來自客戶端的確認(rèn)序號 + 1。服務(wù)端收到確認(rèn)信息后,進(jìn)入已經(jīng)連接的狀態(tài)。

          在第三步的確認(rèn)分組中,是可以攜帶要發(fā)送的數(shù)據(jù)的。

          連接終止標(biāo)志FIN:用來關(guān)閉連接,當(dāng)一端完成數(shù)據(jù)發(fā)送任務(wù)后會發(fā)送一個FIN標(biāo)志來終止連接,但因為TCP在兩個方向(C-S,S-C)上會有數(shù)據(jù)傳遞,每個方向有各自的發(fā)送FIN & 確認(rèn)關(guān)閉流程,所以會有四次交互,也稱為四次揮手。

          1. 如果客戶端應(yīng)用層的數(shù)據(jù)發(fā)送完畢,會導(dǎo)致客戶端的TCP報文發(fā)送一個FIN,告知服務(wù)器準(zhǔn)備關(guān)閉數(shù)據(jù)傳送。
          2. 服務(wù)器接收到這個標(biāo)志后,它發(fā)回一個ACK,確認(rèn)序號為收到的序號加1,同時TCP還要向應(yīng)用程序發(fā)一個文件結(jié)束符。
          3. 此時服務(wù)器關(guān)閉這個方向的連接,導(dǎo)致它的TCP也會發(fā)送一個FIN。
          4. 客戶端接收到之后發(fā)回一個確認(rèn)ACK,序號為收到的序號 + 1,連接完全關(guān)閉。

          TCP段序號與確認(rèn)序號保證了數(shù)據(jù)的順序,檢驗和確保數(shù)據(jù)的完整性,緊急指針保證緊急數(shù)據(jù)可被及時處理。另外,TCP還有一些超時重傳、 擁塞避免、慢啟動的機(jī)制,都可以保證分組數(shù)據(jù)按照順序完整的傳到目標(biāo)端。

          網(wǎng)絡(luò)層-IP

          如果說TCP分組是包裝貨物的集裝箱,那么IP就是運送集裝箱的卡車。IP協(xié)議提供了兩個節(jié)點之間的連接,保證將TCP數(shù)據(jù)盡可能快地從源端送到終端,但卻不能保證傳輸?shù)目煽啃浴?/p>

          IP層會將上層傳過來的TCP分組封裝,帶上自己的首部,再進(jìn)行選路、是否分片以及重組的工作,最終到達(dá)目的地,這個過程中,IP首部起了重要的作用,下面讓我們看一下首部的結(jié)構(gòu)。

          IP首部

          06385938febc392c4609275608912bec.webp

          版本:表示當(dāng)前IP協(xié)議的版本,目前版本號是4,還有一種是6,也就是IPV4和IPV6,如果發(fā)送和接收這兩端的版本不一致,那么當(dāng)前IP數(shù)據(jù)報會被丟棄。

          首部長度:整個首部的長度,最長為60字節(jié)。

          服務(wù)類型(TOS):用來區(qū)分服務(wù)的類型,但其實IP層在工作的時候一直沒有實際使用過,現(xiàn)有的TOS只有4bit的子字段,和1bit的未用位。未用位必須置為0。TOS的4個bit中只能將一個置成1,用來表示當(dāng)前服務(wù)類型。4bit對應(yīng)的4個服務(wù)類型分別為:最小時延、最大吞吐量、最高可靠性和最小費用。

          總長度:表示當(dāng)前的數(shù)據(jù)報報文的總長度,單位為字節(jié),可以結(jié)合首部長度計算出報文內(nèi)數(shù)據(jù)的大小以及起始位置。

          下面這三個首部字段涉及到IP數(shù)據(jù)報的分片與重組過程,由于網(wǎng)絡(luò)層一般會限制每個數(shù)據(jù)幀的最大長度,IP層發(fā)送數(shù)據(jù)報會在選路的同時查詢當(dāng)前設(shè)備網(wǎng)絡(luò)層的每個數(shù)據(jù)幀的最大傳輸長度,一旦超出,數(shù)據(jù)報就會被進(jìn)行分片,到達(dá)目的地之后再進(jìn)行重組,此時就會用以下三個字段作為重組依據(jù)。需要注意的是:因為存在選路的過程,數(shù)據(jù)報經(jīng)過的每層路由設(shè)備對于數(shù)據(jù)幀的最大傳輸長度都不同,所以分片可能發(fā)生在任意一次選路的過程中。

          分組標(biāo)識:這個標(biāo)識相當(dāng)于ID,每成功發(fā)送一個分片,IP層就會把這個分組ID加1。

          標(biāo)志:共占用三位,分別是R、D、M,R目前還沒有被使用,有用的是D、和M。這個字段表示了數(shù)據(jù)報的分片行為。D如果為1的話,表示數(shù)據(jù)無需分片,一次傳輸完;M如果為1,表示數(shù)據(jù)是分片的,后邊還有數(shù)據(jù),當(dāng)它為0時,就表示當(dāng)前數(shù)據(jù)報是最后一個分片,或者只有這一個分片。

          片偏移:標(biāo)識了當(dāng)前分片距離原始數(shù)據(jù)報開始處的位置,分片之后,每一片的總長度會改成這一片的長度值,而不是整個數(shù)據(jù)報的長度。

          生存時間:(TTL) 可以決定數(shù)據(jù)報是否被丟棄。因為IP發(fā)送數(shù)據(jù)是逐跳的,數(shù)據(jù)有可能在被設(shè)置了路由功能的不同的IP層之間轉(zhuǎn)發(fā),所以生存時間表示了數(shù)據(jù)報最多個可以經(jīng)過多少個處理過它的路由,每經(jīng)過一層路由,值減去1,當(dāng)值為0時數(shù)據(jù)報就被丟棄,并且發(fā)送一個帶有錯誤消息的報文(ICMP,IP層的組成部分,被用來傳遞一些錯誤信息)給源端。生存時間可以有效解決數(shù)據(jù)報在一個路由環(huán)路中一直轉(zhuǎn)發(fā)的問題。

          首部檢驗和:校驗數(shù)據(jù)報的完整性,發(fā)送端對首部進(jìn)行求和,將結(jié)果存在檢驗和中,接收端再計算一遍,如果計算結(jié)果與存在檢驗和中的結(jié)果一致,則說明傳輸過程是OK的,否則這個數(shù)據(jù)報就會被丟棄。

          上層協(xié)議:決定了接收端在分用的時候?qū)?shù)據(jù)交給哪個上層協(xié)議去處理,例如TCP或者UDP。

          源IP:記錄了發(fā)送端的IP,在回送錯誤消息時用到。

          目的IP:表示目的IP,每一次選路都要以它來做決策。

          路由選擇

          因為IP首部只包含了目的IP地址,并不體現(xiàn)完整的路徑,當(dāng)向外發(fā)送數(shù)據(jù)時,IP層會根據(jù)目的IP在本機(jī)路由表中的查詢結(jié)果來做出選路決策,數(shù)據(jù)報會逐跳地被運送到目的地,這里的每一跳,就是一次路由選擇。

          IP層既可配置成路由器,也可以配置成主機(jī)。當(dāng)配置成路由功能時,可以對數(shù)據(jù)報進(jìn)行轉(zhuǎn)發(fā),配置成主機(jī)時,如果目的IP不是本機(jī)IP,數(shù)據(jù)報會被丟棄。

          具有路由功能的IP層在當(dāng)目標(biāo)IP不是本機(jī)地址的時候是根據(jù)什么判斷轉(zhuǎn)發(fā)到哪一站呢?要理解這個問題,需要先明白路由表的結(jié)構(gòu),以下是IP層維護(hù)的路由表,(windows系統(tǒng)可以在控制臺輸入netstat -r來查看路由表)

          Destination Gateway Flags Refcnt Use Interface
          140.252.13.65 140.252.13.35 UGH 0 0 emd0
          127.0.0.1 127.0.0.1 UH 1 0 lo0
          default 140.252.13.33 UG 0 0 emd0
          140.252.13.32 140.252.13.34 U 4 25043 emd0

          (路由表數(shù)據(jù)來源于《TCP/IP詳解卷一:協(xié)議》)

          • Destination(目的IP):表示IP數(shù)據(jù)報最終要到達(dá)或者經(jīng)過的網(wǎng)絡(luò)地址或者主機(jī)地址。
          • Gateway(下一跳地址):當(dāng)前維護(hù)路由表設(shè)備的相鄰路由器的地址
          • Flags(標(biāo)志):表示當(dāng)前這一條路由記錄的屬性,具體用五個不同的標(biāo)志來表示:
            • U:該路由可以使用
            • G:如果有這個標(biāo)志,表示是下一跳是一個網(wǎng)關(guān),如果沒有,表示下一跳是和當(dāng)前設(shè)備在一個網(wǎng)段,也就是可以直接把數(shù)據(jù)報發(fā)過去
            • H: 下一跳是一個主機(jī)還是一個網(wǎng)絡(luò),有這個標(biāo)志,表示主機(jī),沒有,則表示下一跳的路由是一個網(wǎng)絡(luò)
            • D:該路由是由重定向報文創(chuàng)建的
            • M:該路由已被重定向報文修改
          • Interface:當(dāng)前路由項的物理端口

          每收到一個數(shù)據(jù)報時候,IP層就會根據(jù)目的IP在路由表里查詢,根據(jù)查詢狀態(tài)會導(dǎo)向三種結(jié)果:

          1. 找到了與目的IP完全匹配的路由項,將報文發(fā)給該路由項的下一站路由(Gateway)或者網(wǎng)絡(luò)接口(Interface)
          2. 找到了與目的IP的網(wǎng)絡(luò)號匹配的路由項,將報文發(fā)給該路由項的下一站路由(Gateway)或者網(wǎng)絡(luò)接口(Interface)
          3. 前兩者都沒有找到,就看路由表里有沒有默認(rèn)路由項(default),有的話發(fā)給它指定的下一站路由(Gateway)

          要是上邊三個都沒有結(jié)果,那么數(shù)據(jù)報就不能被發(fā)送。IP數(shù)據(jù)報就是這樣一跳一跳地被送往目的主機(jī)的,但數(shù)據(jù)報有固有的長度,一旦超出了目的主機(jī)的MTU,就會被分片。

          數(shù)據(jù)報分片的概念

          TCP在進(jìn)行握手的時候,會根據(jù)目的端IP層的最大傳輸單元(MTU)來決定TCP數(shù)據(jù)每次能傳輸?shù)淖畲髷?shù)據(jù)量(MSS),之后TCP會對數(shù)據(jù)依照MSS來進(jìn)行分組,每個分組會被包裝進(jìn)一個IP數(shù)據(jù)報內(nèi)。當(dāng)IP數(shù)據(jù)報經(jīng)過選路過程中的任意一層路由時,有可能被MTU限制住從而被分片,這時IP首部的3bit標(biāo)志中的M標(biāo)志被置為1,表示需要分片。每個分片的首部基本一樣,只是片偏移有所不同。依據(jù)片偏移,這些分片在目的端被重組成一個完整的IP數(shù)據(jù)報(一個TCP分組)。IP傳輸是無序的,所以得到的數(shù)據(jù)報也是無序的,但如果數(shù)據(jù)完整,TCP會根據(jù)首部中的字段對其進(jìn)行排序。一旦IP分片丟失,IP層無法組成完整的數(shù)據(jù)報,就會告訴TCP層,TCP進(jìn)行重傳。

          當(dāng)IP層將數(shù)據(jù)封裝好之后,只有目標(biāo)主機(jī)的IP地址。光有IP地址并不能直接把數(shù)據(jù)報發(fā)送過去,因為每一臺硬件設(shè)備都有自己的MAC地址,是一個48bit的值。現(xiàn)在知道目標(biāo)IP的地址,需要找到這個IP對應(yīng)的MAC地址。這個過程要通過查詢路由表,再結(jié)合鏈路層的ARP協(xié)議,最終獲得目標(biāo)IP對應(yīng)的MAC地址。

          地址解析協(xié)議:ARP

          IP只能讓數(shù)據(jù)在邏輯端點之間流動,但是IP之下還有網(wǎng)絡(luò)接口層,這一層也有自己的地址(MAC地址:用于在網(wǎng)絡(luò)中唯一標(biāo)識一個網(wǎng)卡),從IP地址到MAC地址需要一個轉(zhuǎn)換的過程,ARP就是提供這一服務(wù)的。

          ARP協(xié)議實現(xiàn)了從IP地址到MAC地址的映射。一開始,起點并不知道目標(biāo)的MAC地址,只有目標(biāo)IP,要獲取這個地址就涉及到了ARP的請求和應(yīng)答。同樣,ARP也有自己的分組,先看一下分組格式。

          ARP分組格式

          c2760b7843ba1cc33b5ecf1d5837b601.webp

          以太網(wǎng)目的地址:目的端的MAC地址,當(dāng)ARP緩存表中沒有的時候,這里為廣播地址。

          以太網(wǎng)源地址:發(fā)送端的MAC地址。

          幀類型:不同的幀類型有不同的格式和MTU值,不同的類型有不同的編號,這里ARP對應(yīng)的編號是0x0806。

          硬件類型:指鏈路層網(wǎng)絡(luò)類型,1為以太網(wǎng)。

          協(xié)議類型:指的是要轉(zhuǎn)換的地址類型,0x0800為IP地址。比如將以太網(wǎng)地址轉(zhuǎn)換為IP地址。

          op(操作類型):有四種,分別是ARP請求(1),ARP應(yīng)答(2),RARP請求(3),RARP應(yīng)答(4)。

          源MAC地址:表示發(fā)送端MAC地址。

          源IP地址:表示發(fā)送端IP地址。

          目的以太網(wǎng)地址:表示目標(biāo)設(shè)備的MAC物理地址。

          目的IP地址:表示目標(biāo)設(shè)備的IP地址。

          當(dāng)兩臺設(shè)備發(fā)送報文之前,源端的鏈路層會用ARP協(xié)議去詢問目的端的MAC地址,ARP會將一個請求廣播出去,以太網(wǎng)上的每一個主機(jī)都會收到這份廣播,廣播的目的是詢問目標(biāo)IP的MAC地址,內(nèi)容主要是先介紹自己的IP和MAC地址,再詢問如果你有目標(biāo)IP,請回復(fù)你的硬件地址。如果一個主機(jī)收到廣播后看到自己有這個IP,并且請求內(nèi)有源IP和MAC地址,那么就會向源主機(jī)回應(yīng)一個ARP應(yīng)答。如果沒有目標(biāo)IP,就會丟棄這個請求。可以看出請求是向外廣播的,而應(yīng)答是單獨回應(yīng)的。

          但不能每次通信之前都去經(jīng)歷一次請求-應(yīng)答過程,在成功地接收到應(yīng)答之后,IP和MAC地址的映射關(guān)系就會緩存在ARP緩存表中,有效期一般為20分鐘,便于網(wǎng)絡(luò)層下次直接進(jìn)行封裝,所以,完整的過程應(yīng)該是:

          IP層接收到TCP分組后,發(fā)送或者封裝之前,通過查詢路由表:

          1. 當(dāng)目標(biāo)IP和自己在同一個網(wǎng)段時,先去ARP緩存表里找有沒有目標(biāo)IP對應(yīng)的MAC地址,有的話交給鏈路層進(jìn)行封裝發(fā)送出去。如果緩存表內(nèi)沒有,進(jìn)行廣播,獲得MAC地址后緩存起來,IP層再對TCP進(jìn)行封裝,然后交給鏈路層再封裝發(fā)送出去。
          2. 當(dāng)目標(biāo)IP和自己不在同一個網(wǎng)段,需要將報文發(fā)給默認(rèn)的網(wǎng)關(guān)。如果ARP緩存表中有網(wǎng)關(guān)IP對應(yīng)的MAC地址,那么交給鏈路層進(jìn)行封裝發(fā)送出去。如果沒有,進(jìn)行廣播,獲得地址后緩存起來,IP層再對TCP進(jìn)行封裝,然后交給鏈路層再封裝發(fā)送出去。

          以太網(wǎng)數(shù)據(jù)幀

          上面所有東西都準(zhǔn)備好了,封裝發(fā)送的其實是以太網(wǎng)數(shù)據(jù)幀。以太網(wǎng)目的地址、以太網(wǎng)源地址、幀類型這三者組成了幀首部。在首部之前還會插入前同步碼和幀開始定界符,告知接收端做一些準(zhǔn)備工作。幀檢驗序列 FCS被添加進(jìn)尾部,用來檢測幀是否出錯。

          結(jié)構(gòu)

          f8b44d63d8ad1ebbdb05e873cd8be1af.webp

          前同步碼:協(xié)調(diào)終端接收適配器的時鐘頻率,讓它與發(fā)送端頻率相同。

          幀開始定界符:幀開始的標(biāo)志,表示幀信息要來了,準(zhǔn)備接收。

          目的地址:接收幀的網(wǎng)絡(luò)適配器的MAC地址,接收端收到幀時,會首先檢查目的地址與本機(jī)地址是否相符,不是的話就會丟棄。

          源地址:發(fā)送端設(shè)備的MAC地址。

          類型:決定接收到幀之后將數(shù)據(jù)交由那種協(xié)議處理。

          數(shù)據(jù):交給上層的數(shù)據(jù)。在本文的場景中指IP數(shù)據(jù)報。

          幀檢驗序列:檢測這一幀是否出錯,發(fā)送方計算幀的循環(huán)冗余碼校驗(CRC)值,把這個值寫到幀里。接收方計算機(jī)重新計算 CRC,與 FCS 字段的值進(jìn)行比較。如果兩個值不相同,則表示傳輸過程中發(fā)生了數(shù)據(jù)丟失或改變。這時,就需要重新傳輸這一幀。

          傳輸和接收

          1. 接收到上層傳過來的數(shù)據(jù)報之后,根據(jù)MTU以及數(shù)據(jù)報大小來決定是否分割成小塊,也就是IP數(shù)據(jù)報被分片的過程。
          2. 把數(shù)據(jù)報(塊)封裝成一幀,傳給底層組件,底層組件將幀轉(zhuǎn)換為比特流,并發(fā)送出去。
          3. 以太網(wǎng)上的設(shè)備接收到幀,檢查幀里邊的目標(biāo)地址,如果與本機(jī)地址匹配,幀就會被處理,一層一層向上傳遞(分用過程)。

          最后

          一個網(wǎng)絡(luò)請求從源端一層層封裝,再到終端一層層拆分,最后的所有過程基本梳理清楚,文章只是簡單梳理了一下大概流程,并且只以HTTP報文通過TCP協(xié)議經(jīng)過IP傳送這一過程為例,實際還有很多概念沒有覆蓋,比如鏈路層的尾部封裝、 IP的動態(tài)選路、逆地址解析協(xié)議RARP、UDP協(xié)議相關(guān)的概念,建議大家可以閱讀下面列出的參考資料,相信會有更多收獲。

          - End -
          本公眾號全部博文已整理成一個目錄,請在公眾號后臺回復(fù)「m」獲取!
          推薦閱讀:1、欠阿里云一分錢,會是什么樣的后果?
          2、90 行 Python 代碼,讓張小龍的微信地球轉(zhuǎn)起來!
          3、知乎熱議:月薪下到5千,上到3萬,計算機(jī)專業(yè)錢景究竟如何?網(wǎng)友:虛高
          4、太贊了!一份適合程序員的精選面試題清單。
          5、推薦 33 個 IDEA 最牛配置!
          6、最受 IT 公司歡迎的 30 款開源軟件關(guān)注微信公眾號『杰哥的IT之旅』,后臺回復(fù)“1024”查看更多內(nèi)容,回復(fù)“微信”添加我微信。

          點個[在看],是對杰哥最大的支持!
          瀏覽 142
          點贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  无码破解一区二区三区在线播报 | 国内免费毛片一区二区 | 中文字幕A V在线播放 | 青青草在线视频免费在线观看 | 淫淫AV|