一个 http 请求的曲折经历
??點擊上方?好好學java?,選擇?星標?公眾號
重磅資訊、干貨,第一時間送達 今日推薦:本人真實經歷:面試了20家大廠之后,發現這樣介紹項目經驗,顯得項目很牛逼!作者:nero 鏈接:https://segmentfault.com/a/1190000022514313寫在前面
作為程序員的我們每天都在和網絡請求打交道,而前端程序員接觸的最多的就是HTTP請求。平時工作中,處理網絡請求之類的操作是最多的了。但是一個請求從客戶端發出到被服務端處理、再回送響應,再被客戶端接收這一個閉環的底層細節可能并沒有深究過,本篇文章是我的一篇讀書筆記,總結出來恰好涉及到了這一過程,分享出來希望可以對大家有所啟發。
文中某些點如果表述有誤,歡迎指出來,不勝感激。
從一個經典的面試題說起
從輸入URL到頁面展現的過程
輸入URL后,會先進行域名解析。優先查找本地host文件有無對應的IP地址,沒有的話去本地DNS服務器查找,還不行的話,本地DNS服務器會去找根DNS服務器要一個域服務器的地址進行查詢,域服務器將要查詢的域名的解析服務器地址返回給本地DNS,本地DNS去這里查詢就OK了。
瀏覽器拿到服務器的IP地址后,會向它發送HTTP請求。HTTP請求經由一層層的處理、封裝、發出之后,最終經由網絡到達服務器,建立TCP/IP連接,服務器接收到請求并開始處理。
服務器構建響應,再經由一層層的處理、封裝、發出后,到達客戶端,瀏覽器處理請求。
瀏覽器開始渲染頁面,解析HTML,構建render樹,根據render樹的節點和CSS的對應關系,進行布局,繪制頁面。
這4個步驟包含了一個HTTP請求的完整生命周期,文章著重介紹第2步和第3步,也就是請求是如何在兩個物理端點之間進行通信的。數據的發出和接收必然會經歷一些處理、解析的過程,這些過程在系統的不同層次進行。
分層
一個HTTP請求從源端發出到在終端接收的處理過程都是要經過以下四層。其中每一層都有各自的協議。
我們先來理解一下協議是什么,協議是經過約定,雙方共同承認,并且需要共同遵守的規則。上面的每一層,都有各自的協議,協議的執行者是通信鏈路兩端內的對應層。每一層通過協議來理解數據,并進行處理。
上圖中只舉例出了最常見的協議,實際上每一層都有細分的協議:
應用層:應用程序負責將數據以相應規則(協議)進行包裝,發給傳輸層
HTTP:超文本傳輸協議
FTP:文件傳輸協議
SMTP:簡單郵件傳送協議
SNMP:簡單網絡管理協議
傳輸層:負責將應用層傳過來的數據進行分組,為確保終端接收數據的順序和完整性,會對每個分組進行標記,交給網絡層
TCP:傳輸控制協議
UDP:用戶數據協議
網絡層:負責將傳輸層發來的數據分組發送到目標終端
ICMP:Internet互聯網控制報文協議
IGMP:Internet組管理協議
IP:網際協議
鏈路層:為網絡層發送和接收數據單元
ARP:地址解析協議
RARP:逆地址解析協議
封裝和分用
數據在經過每一層的時候都要被對應的協議包裝,到達終端的時候,要一層一層的解包。這兩個過程叫封裝和分用。
發送時,用戶數據被HTTP封裝為報文,每一層會將上層傳過來的報文作為本層的數據塊,并添加自己的首部,其中包含了協議標識,這一整體作為本層報文向下傳遞。
接收時,數據自下而上流動,經過每一層時被去掉報文首部,根據報文標識確定正確的上層協議,最終到應用層被應用程序處理。
封裝
源端發送HTTP報文時,報文會以數據流的形式通過一條已經打開的TCP連接按序傳輸,TCP收到數據流后會將其分割成小的數據塊,每個小塊被添加的TCP首部與數據塊共同組成了TCP分組,分組經由網絡層發送,網絡層遵循IP協議,當收到分組發送請求后,會將分組其放入IP數據報,填充報頭,將數據報發經由鏈路層發送出去。
這一過程經過每層的時候都會被增加一些首部信息,有時還需要增加尾部信息,每一層都會把數據封裝到各自的報文中, 并在報文首部添加協議標識,這個過程叫封裝。
分用
終端接收到一個以太網數據幀時,數據自底層向上流動,去掉發送時各層協議加上的報文首部,每層協議都要檢查報文首部的協議標識,從而確定上層協議,保證數據被正確處理,這個過程叫分用。
終端從鏈路層接收到數據請求后,進入網絡層對數據進行解析,交給給傳輸層,校驗分組順序和完整性,從數據塊中取出數據,得到HTTP報文,交給應用層進行處理。這個過程會逐層剝離報頭還原數據。
逐層分析
我們已經知道,數據是從源端自上而下到終端自下而上被一層層處理的,現在就來看一下每層都做了什么事情。
HTTP
HTTP屬于應用層,用戶觸發交互所產生的行為數據和服務端對此的響應都由它封裝成HTTP報文,再交由下層協議進行處理。報文的作用是客戶端與服務端溝通的載體,雙方都要遵循統一規則對信息進行處理,這一規則稱為HTTP。
客戶端與服務端的交互往往非常復雜,為了使雙方都能高效、明確、安全地通信(例如傳遞意圖與狀態、承載數據、攜帶認證信息、控制連接行為與緩存),需要依賴報文中的結構來實現,下面先從結構開始看。
報文結構
HTTP報文的結構分為請求和響應兩種,請求報文封裝用戶操作產生的動作,告知服務器應采取什么行為,響應報文來告知客戶端請求的結果。
請求報文格式:
<method>?<request-url>?<version>?//?起始行格式 <headers>?//?首部 <body>?//?實體響應報文格式:
<method>?<status>?<reason-phrase>?//?起始行格式 <headers>?//?首部 <body>?//?實體起始行
報文的起始行表明了報文的開始,請求和響應各自的起始行的格式也不相同。
請求報文的起始行說明要做什么,結構為方法 + 請求URL + 協議版本,中間用空格做分隔:
GET?/api/nht/blog/example?HTTP/1.1響應報頭的起始行說明發生了什么,結構為協議版本 + 狀態碼 + 描述文本,中間用空格做分隔:
HTTP/1.1?200?OK方法與狀態碼
方法來告訴服務端請求報文要做的事情,狀態碼來通知客戶端服務端依據請求報文完成動作之后的大致結果。常見的HTTP方法如下:
| GET | 從服務端獲取資源 | 無 |
| HEAD | 只獲取資源頭部 | 無 |
| POST | 向服務端發送數據 | 有 |
| PUT | 將客戶端發送的數據存到服務端,應用場景多為修改 | 有 |
| OPTIONS | 對服務端進行預檢,例如服務端支持哪些方法 | 無 |
| DELETE | 從服務端刪除資源 | 無 |
請求完成時,響應報文中會有一個狀態碼,用來表示此次請求的狀態,是成功了還是失敗了,或者時需要重定向。狀態碼的范圍從100到599, 其中有部分是已經定義的。不同的范圍表示的含義也不同:
| 100~199 | 100~101 | 信息提示 |
| 200~299 | 200~206 | 成功 |
| 300~399 | 300~305 | 重定向 |
| 400~499 | 400~415 | 客戶端錯誤 |
| 500~599 | 500~505 | 服務端錯誤 |
首部
首部是請求和響應報文中的一些信息,形式為鍵值對,每對鍵值結尾是CRLF換行符,它決定了請求或者響應報文的屬性,比如Content-Type表明了請求主體的數據類型,Date說明了請求的創建時間。客戶端與服務端通過首部來協商具體行為。可以根據請求、響應、結構等,將首部分為五種。
請求首部:是放在請求報文中的首部,它被用來告訴服務端一些信息。
響應首部:為客戶端提供一些可能用到的信息。
通用首部:請求與響應報文都包含的首部,例如Date首部
實體首部:對于報文實體主體部分的描述,比如Content-Type,表明其數據類型。
擴展首部:開發者自己添加的首部字段,用來滿足定制化需求。
實體
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! --------------------------------實體部分是可選的,它被用來運送請求或者響應的數據,實體由實體首部 + 實體主體組成,實體首部對實體主體做描述。HTTP/1.1定義了以下的基本實體首部字段:
Content-Type: 實體主體中的數據類型。
Content-Length: 實體主體的長度或者大小。
Content-Language: 和傳輸的數據最匹配的語言。
Content-Encoding: 來標識服務端編碼時所用的編碼方式。
Content-Location: 要返回的數據的地址。
Content-Range: 如果是部分實體,用來標記它是實體的哪個部分。
Content-MD5: 實體主體內容的校驗和。
Last-Modified: 所傳輸內容在服務器上創建或者最后修改的日期時間。
Expires: 實體數據試下的日期時間。
Allow: 所請求資源允許的請求方法。
ETag: 資源的特定版本的標識符。可以讓緩存更高效,并節省帶寬。
Cache-Control: 控制緩存機制的指令。
以上是HTTP報文包含的主要結構,當請求報文到達服務器時,服務器會對報文中的內容解析出來,根據方法、資源路徑、首部、和主體來處理請求,然后通過對請求資源的訪問結果,來構建響應,回送給客戶端。
傳輸層-TCP
HTTP連接是建立在TCP連接的基礎之上的,TCP提供可靠的數據連接。當要傳輸一個HTTP報文時,報文數據會以流的形式通過一條已經打開的TCP連接按順序傳輸,TCP會將收到的數據分成小塊,每塊是一個TCP分組。
由于數據是分成小塊發送的,所以完整可靠的數據傳輸主要體現在:分組是否完整、分組順序是否正常、分組是否損壞、分組數據是否重復。這些可以通過TCP的檢驗和、序列號、確認應答、重發控制、連接管理和窗口機制來控制。
TCP是傳輸控制協議,傳輸控制主要依賴首部包含的6個標志,它們控制報文的傳輸狀態,以及發送端和接收端應對數據采取的動作。當它們的值為1時,標志對應的各自功能才允許被執行,比如當URG為1時,報文首部的緊急指針部分才有效。
URG 緊急指針
ACK 確認序號有效
PSH 接收方應該盡快將這個報文段交給應用層。
RST 重建連接
SYN 同步序號用來發起一個連接
FIN 發端完成發送任務
源端口和目的端口: 標識發送方和接收方的端口號,一個TCP連接通過4個值確認:源IP、源端口、目的IP、目的端口,其中源IP和目的IP包含在IP分組內。
首部長度: 表示TCP首部的字節長度,也能標記出從多少個字節開始,才是需要傳輸的數據。
TCP段序號: 本段報文發送的數據第一個字節的序號,每段報文中的數據的每個字節都有序號,第一個字節的序號從0開始,依次加1,加到2的32次方減1后再次從0開始。
TCP段確認序號 : 當首部標志ACK為1時,確認序號有效。TCP段被接收端接收后,會回送給發送端一個確認號,為上次接受的最后一個字節序號加1。
檢驗和: 由發送端計算,接收端驗證,如果接收方檢測到檢驗和不正確,表明該TCP段可能有損壞,會被丟棄,同時接收端向回送一個重復的確認號(與最近的一次正確的報文傳輸的確認號重復),表明接收到的TCP段是錯誤的,并告知自己希望收到的序號。這時發送端需要立即重傳出錯的TCP段。
緊急指針: 當首部標志URG為1時,緊急指針有效,表示發送端向接收端要發送緊急數據。緊急指針是一個正偏移量,它和TCP段序號相加,計算出緊急數據的最后一個字節的序號。比如接收方接收到數據,從序號為1000的字節開始讀取,緊急指針為1000,那么緊急數據就是序號從1000到2000之間的字節。這些數據由接收方決定如何處理。
窗口尺寸: 決定了TCP一次成塊數據流的吞吐量。需要注意的是,它表示的是發送一方的允許對方發送的數據量,比如發送方首部中的窗口大小為1000,就表示發送方最多可以接受對方發來的1000個字節的數據量。這與發送方的數據緩存空間有關,會影響TCP的性能。
首部標志PSH: 如果需要告訴接收方將數據立即全部提交給接收進程,發送方需要將PSH置為1,這里的數據是和PSH一起傳送的數據以及之前接收到的全部數據。如果接收方收到了PSH為1的標志,需要立即將數據提交給接收進程,不用再等待有沒有其他數據進來。
復位標志RST: 當RST為1時,表示連接出現了異常情況,接收方將終止連接,通知應用層重新建立連接。
同步序號SYN: 用來建立連接,涉及到TCP的三次握手。
開始建立連接時,客戶端向服務器發送一個TCP分組,分組首部的SYN為1,并攜帶一個初始序號,表明這是一個連接請求。
如果服務器接受了連接,會向客戶端發送一個TCP分組,分組中會包含SYN和ACK,都為1,同時包含一個確認序號,值為來自客戶端的初始序號 + 1,表示連接已經被接受。
客戶端收到上一步發來的分組后,會再向服務器發送一段確認報文分組,ACK為1,會再次攜帶確認序號,值是第二步來自客戶端的確認序號 + 1。服務端收到確認信息后,進入已經連接的狀態。
在第三步的確認分組中,是可以攜帶要發送的數據的。
連接終止標志FIN: 用來關閉連接,當一端完成數據發送任務后會發送一個FIN標志來終止連接,但因為TCP在兩個方向(C-S,S-C)上會有數據傳遞,每個方向有各自的發送FIN & 確認關閉流程,所以會有四次交互,也稱為四次揮手。
如果客戶端應用層的數據發送完畢,會導致客戶端的TCP報文發送一個FIN,告知服務器準備關閉數據傳送。
服務器接收到這個標志后,它發回一個ACK,確認序號為收到的序號加1,同時TCP還要向應用程序發一個文件結束符。
此時服務器關閉這個方向的連接,導致它的TCP也會發送一個FIN。
客戶端接收到之后發回一個確認ACK,序號為收到的序號 + 1,連接完全關閉。
TCP段序號與確認序號保證了數據的順序,檢驗和確保數據的完整性,緊急指針保證緊急數據可被及時處理。另外,TCP還有一些超時重傳、 擁塞避免、慢啟動的機制,都可以保證分組數據按照順序完整的傳到目標端。
網絡層-IP
如果說TCP分組是包裝貨物的集裝箱,那么IP就是運送集裝箱的卡車。IP協議提供了兩個節點之間的連接,保證將TCP數據盡可能快地從源端送到終端,但卻不能保證傳輸的可靠性。
IP層會將上層傳過來的TCP分組封裝,帶上自己的首部,再進行選路、是否分片以及重組的工作,最終到達目的地,這個過程中,IP首部起了重要的作用,下面讓我們看一下首部的結構。
IP首部
版本: 表示當前IP協議的版本,目前版本號是4,還有一種是6,也就是IPV4和IPV6,如果發送和接收這兩端的版本不一致,那么當前IP數據報會被丟棄。
首部長度: 整個首部的長度,最長為60字節。
服務類型(TOS): 用來區分服務的類型,但其實IP層在工作的時候一直沒有實際使用過,現有的TOS只有4bit的子字段,和1bit的未用位。未用位必須置為0。TOS的4個bit中只能將一個置成1,用來表示當前服務類型。4bit對應的4個服務類型分別為:最小時延、最大吞吐量、最高可靠性和最小費用。
總長度: 表示當前的數據報報文的總長度,單位為字節,可以結合首部長度計算出報文內數據的大小以及起始位置。
下面這三個首部字段涉及到IP數據報的分片與重組過程,由于網絡層一般會限制每個數據幀的最大長度,IP層發送數據報會在選路的同時查詢當前設備網絡層的每個數據幀的最大傳輸長度,一旦超出,數據報就會被進行分片,到達目的地之后再進行重組,此時就會用以下三個字段作為重組依據。需要注意的是:因為存在選路的過程,數據報經過的每層路由設備對于數據幀的最大傳輸長度都不同,所以分片可能發生在任意一次選路的過程中。
分組標識: 這個標識相當于ID,每成功發送一個分片,IP層就會把這個分組ID加1。
標志: 共占用三位,分別是R、D、M,R目前還沒有被使用,有用的是D、和M。這個字段表示了數據報的分片行為。D如果為1的話,表示數據無需分片,一次傳輸完;M如果為1,表示數據是分片的,后邊還有數據,當它為0時,就表示當前數據報是最后一個分片,或者只有這一個分片。
片偏移: 標識了當前分片距離原始數據報開始處的位置,分片之后,每一片的總長度會改成這一片的長度值,而不是整個數據報的長度。
生存時間:(TTL) 可以決定數據報是否被丟棄。因為IP發送數據是逐跳的,數據有可能在被設置了路由功能的不同的IP層之間轉發,所以生存時間表示了數據報最多個可以經過多少個處理過它的路由,每經過一層路由,值減去1,當值為0時數據報就被丟棄,并且發送一個帶有錯誤消息的報文(ICMP,IP層的組成部分,被用來傳遞一些錯誤信息)給源端。生存時間可以有效解決數據報在一個路由環路中一直轉發的問題。
首部檢驗和: 校驗數據報的完整性,發送端對首部進行求和,將結果存在檢驗和中,接收端再計算一遍,如果計算結果與存在檢驗和中的結果一致,則說明傳輸過程是OK的,否則這個數據報就會被丟棄。
上層協議: 決定了接收端在分用的時候將數據交給哪個上層協議去處理,例如TCP或者UDP。
源IP: 記錄了發送端的IP,在回送錯誤消息時用到。
目的IP: 表示目的IP,每一次選路都要以它來做決策。
路由選擇
因為IP首部只包含了目的IP地址,并不體現完整的路徑,當向外發送數據時,IP層會根據目的IP在本機路由表中的查詢結果來做出選路決策,數據報會逐跳地被運送到目的地,這里的每一跳,就是一次路由選擇。
IP層既可配置成路由器,也可以配置成主機。當配置成路由功能時,可以對數據報進行轉發,配置成主機時,如果目的IP不是本機IP,數據報會被丟棄。
具有路由功能的IP層在當目標IP不是本機地址的時候是根據什么判斷轉發到哪一站呢?要理解這個問題,需要先明白路由表的結構,以下是IP層維護的路由表,(windows系統可以在控制臺輸入netstat -r來查看路由表)
| 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 |
(路由表數據來源于《TCP/IP詳解卷一:協議》)
Destination(目的IP):表示IP數據報最終要到達或者經過的網絡地址或者主機地址。
Gateway(下一跳地址):當前維護路由表設備的相鄰路由器的地址
Flags(標志):表示當前這一條路由記錄的屬性,具體用五個不同的標志來表示:
U:該路由可以使用
G:如果有這個標志,表示是下一跳是一個網關,如果沒有,表示下一跳是和當前設備在一個網段,也就是可以直接把數據報發過去
H: 下一跳是一個主機還是一個網絡,有這個標志,表示主機,沒有,則表示下一跳的路由是一個網絡
D:該路由是由重定向報文創建的
M:該路由已被重定向報文修改
Interface:當前路由項的物理端口
每收到一個數據報時候,IP層就會根據目的IP在路由表里查詢,根據查詢狀態會導向三種結果:
找到了與目的IP完全匹配的路由項,將報文發給該路由項的下一站路由(Gateway)或者網絡接口(Interface)
找到了與目的IP的網絡號匹配的路由項,將報文發給該路由項的下一站路由(Gateway)或者網絡接口(Interface)
前兩者都沒有找到,就看路由表里有沒有默認路由項(default),有的話發給它指定的下一站路由(Gateway)
要是上邊三個都沒有結果,那么數據報就不能被發送。IP數據報就是這樣一跳一跳地被送往目的主機的,但數據報有固有的長度,一旦超出了目的主機的MTU,就會被分片。
數據報分片的概念
TCP在進行握手的時候,會根據目的端IP層的最大傳輸單元(MTU)來決定TCP數據每次能傳輸的最大數據量(MSS),之后TCP會對數據依照MSS來進行分組,每個分組會被包裝進一個IP數據報內。當IP數據報經過選路過程中的任意一層路由時,有可能被MTU限制住從而被分片,這時IP首部的3bit標志中的M標志被置為1,表示需要分片。每個分片的首部基本一樣,只是片偏移有所不同。依據片偏移,這些分片在目的端被重組成一個完整的IP數據報(一個TCP分組)。IP傳輸是無序的,所以得到的數據報也是無序的,但如果數據完整,TCP會根據首部中的字段對其進行排序。一旦IP分片丟失,IP層無法組成完整的數據報,就會告訴TCP層,TCP進行重傳。
當IP層將數據封裝好之后,只有目標主機的IP地址。光有IP地址并不能直接把數據報發送過去,因為每一臺硬件設備都有自己的MAC地址,是一個48bit的值。現在知道目標IP的地址,需要找到這個IP對應的MAC地址。這個過程要通過查詢路由表,再結合鏈路層的ARP協議,最終獲得目標IP對應的MAC地址。
地址解析協議:ARP
IP只能讓數據在邏輯端點之間流動,但是IP之下還有網絡接口層,這一層也有自己的地址(MAC地址:用于在網絡中唯一標識一個網卡),從IP地址到MAC地址需要一個轉換的過程,ARP就是提供這一服務的。
ARP協議實現了從IP地址到MAC地址的映射。一開始,起點并不知道目標的MAC地址,只有目標IP,要獲取這個地址就涉及到了ARP的請求和應答。同樣,ARP也有自己的分組,先看一下分組格式。
ARP分組格式
以太網目的地址: 目的端的MAC地址,當ARP緩存表中沒有的時候,這里為廣播地址。
以太網源地址: 發送端的MAC地址。
幀類型: 不同的幀類型有不同的格式和MTU值,不同的類型有不同的編號,這里ARP對應的編號是0x0806。
硬件類型: 指鏈路層網絡類型,1為以太網。
協議類型: 指的是要轉換的地址類型,0x0800為IP地址。比如將以太網地址轉換為IP地址。
op(操作類型): 有四種,分別是ARP請求(1),ARP應答(2),RARP請求(3),RARP應答(4)。
源MAC地址: 表示發送端MAC地址。
源IP地址: 表示發送端IP地址。
目的以太網地址: 表示目標設備的MAC物理地址。
目的IP地址: 表示目標設備的IP地址。
當兩臺設備發送報文之前,源端的鏈路層會用ARP協議去詢問目的端的MAC地址,ARP會將一個請求廣播出去,以太網上的每一個主機都會收到這份廣播,廣播的目的是詢問目標IP的MAC地址,內容主要是先介紹自己的IP和MAC地址,再詢問如果你有目標IP,請回復你的硬件地址。如果一個主機收到廣播后看到自己有這個IP,并且請求內有源IP和MAC地址,那么就會向源主機回應一個ARP應答。如果沒有目標IP,就會丟棄這個請求。可以看出請求是向外廣播的,而應答是單獨回應的。
但不能每次通信之前都去經歷一次請求-應答過程,在成功地接收到應答之后,IP和MAC地址的映射關系就會緩存在ARP緩存表中,有效期一般為20分鐘,便于網絡層下次直接進行封裝,所以,完整的過程應該是:
IP層接收到TCP分組后,發送或者封裝之前,通過查詢路由表:
當目標IP和自己在同一個網段時,先去ARP緩存表里找有沒有目標IP對應的MAC地址,有的話交給鏈路層進行封裝發送出去。如果緩存表內沒有,進行廣播,獲得MAC地址后緩存起來,IP層再對TCP進行封裝,然后交給鏈路層再封裝發送出去。
當目標IP和自己不在同一個網段,需要將報文發給默認的網關。如果ARP緩存表中有網關IP對應的MAC地址,那么交給鏈路層進行封裝發送出去。如果沒有,進行廣播,獲得地址后緩存起來,IP層再對TCP進行封裝,然后交給鏈路層再封裝發送出去。
以太網數據幀
上面所有東西都準備好了,封裝發送的其實是以太網數據幀。以太網目的地址、以太網源地址、幀類型這三者組成了幀首部。在首部之前還會插入前同步碼和幀開始定界符,告知接收端做一些準備工作。幀檢驗序列 FCS被添加進尾部,用來檢測幀是否出錯。
結構
前同步碼: 協調終端接收適配器的時鐘頻率,讓它與發送端頻率相同。
幀開始定界符: 幀開始的標志,表示幀信息要來了,準備接收。
目的地址: 接收幀的網絡適配器的MAC地址,接收端收到幀時,會首先檢查目的地址與本機地址是否相符,不是的話就會丟棄。
源地址: 發送端設備的MAC地址。
類型: 決定接收到幀之后將數據交由那種協議處理。
數據: 交給上層的數據。在本文的場景中指IP數據報。
幀檢驗序列: 檢測這一幀是否出錯,發送方計算幀的循環冗余碼校驗(CRC)值,把這個值寫到幀里。接收方計算機重新計算 CRC,與 FCS 字段的值進行比較。如果兩個值不相同,則表示傳輸過程中發生了數據丟失或改變。這時,就需要重新傳輸這一幀。
傳輸和接收
接收到上層傳過來的數據報之后,根據MTU以及數據報大小來決定是否分割成小塊,也就是IP數據報被分片的過程。
把數據報(塊)封裝成一幀,傳給底層組件,底層組件將幀轉換為比特流,并發送出去。
以太網上的設備接收到幀,檢查幀里邊的目標地址,如果與本機地址匹配,幀就會被處理,一層一層向上傳遞(分用過程)。
最后
一個網絡請求從源端一層層封裝,再到終端一層層拆分,最后的所有過程基本梳理清楚,文章只是簡單梳理了一下大概流程,并且只以HTTP報文通過TCP協議經過IP傳送這一過程為例,實際還有很多概念沒有覆蓋,比如鏈路層的尾部封裝、 IP的動態選路、逆地址解析協議RARP、UDP協議相關的概念,建議大家可以閱讀下面列出的參考資料,相信會有更多收獲。
參考文章:
《HTTP權威指南》
《TCP/IP詳解 卷一:協議》
以太網數據幀格式(結構)圖解
最后,再附上我歷時三個月總結的?Java 面試 + Java 后端技術學習指南,這是本人這幾年及春招的總結,目前,已經拿到了騰訊等大廠offer,拿去不謝,github 地址:https://github.com/OUYANGSIHAI/JavaInterview
這么辛苦總結,給個star好不好。?點擊閱讀原文,直達
《新程序員》:云原生和全面數字化實踐50位技術專家共同創作,文字、視頻、音頻交互閱讀總結
以上是生活随笔為你收集整理的一个 http 请求的曲折经历的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 本人真实经历:面试了20家大厂之后,发现
- 下一篇: 关于分布式锁的面试题都在这里了