時隔四年,這個系列鴿了四年,我終於覺得我可以按照自己的思路和想法把這個系列完整的表達出來了。
想起四年前,那時候還是2018年的六月份,那時候我還工作不到兩年,那時候我翻譯了RFC2616的部分內容,釋出在了部落格園上,並在翻譯不久後想要開始整理並學習HTTP相關的知識內容,那時候我以為我可以了。
但是在第一篇《真正「搞」懂http協定01之背景故事發布》之後,我發現我對整個系列的內容分佈完全無從下手。這期間我也釋出了很多系列內容(其實就是抄抄書),但是一方面沒有花時間去刻意的學習,另外一方面覺得對於HTTP的瞭解還不足以去寫一個系列的部落格。
剛好,最近想要有一些變化了,所以開始學習HTTP,並且再加上這些年的工作經驗大致對於HTTP有了一定的認識和了解,可以按照自己想要的思路來完成這一系列。
那麼本系列的設想大致是這樣的。
先聊聊HTTP在網際網路絡模型中的位置以及有哪些網際網路絡模型,並且不同的網際網路絡模型是如何分層的,以及整個網際網路絡模型的資料流轉是什麼樣的。嗯~也就是本篇的內容。
下一篇會再講講HTTP的歷史,各階段的HTTP發展及其核心內容,比如各個版本的HTTP都涵蓋了哪些頭欄位,有哪些變化,隨著時間的變遷增加了哪些方法,以及更安全的HTTPS、還有效能更優良的QUIC也就是HTTP3。
以上兩篇內容,核心就是HTTP在空間和時間上是怎樣流轉和發展的,其目的是為了讓大家對於HTTP在空間和時間上處於怎樣的位置,學習HTTP又不能侷限於HTTP。
然後,我會根據HTTP在歷史上的發展,按照時間線,以一個前端開發的角度(主要是因為我也沒別的角度了)帶大家深入的去學習HTTP的各項內容並加以分析。
好啦,敘舊就到此為止,我們正式開始吧。
在第一篇背景故事裡,我簡單的介紹了網際網路絡模型,特別簡單的那種。讓人苦惱的是,網際網路絡模型並不只是單單一種,歷史上的大佬根據不同的場景和階段所產生的不同的需求都對網際網路絡模型加以不同的分層。
那麼這一小節,我們先來簡單的瞭解下什麼是網際網路絡模型。但是在開始聊模型之前,我們得先了解下什麼是網路。
網路,可以說是計算機網路的簡稱,當然,計算機網路是一個很基礎的學科,如果大學是計算機專業的一定學過這些。而我們在工作和生活中最常見的網路就是全球資訊網,也即WWW(World Wide Web),是一個透過網際網路存取的,由許多互相連結的超文字組成的資訊系統。
除了全球資訊網,還有網際網路,區域網,等等等等,而全球資訊網其實是網際網路的一個子集。我們在工作和生活中最常用的就是全球資訊網,我們通常所說的上網,也即是上全球資訊網,它是基於HTTP協定的,傳輸 HTML 等超文字資源的,能力也就被限制在 HTTP 協定之內。
OK,我們基本瞭解了什麼是網路。
但是要了解HTTP處於網路中怎樣的位置,我們還得看看網際網路絡模型是什麼樣的。誒?你叫做網際網路絡模型,不是叫做全球資訊網路模型?說明了什麼?
額~~~你聊網路模型,怎麼聊到TCP/IP了?TCP不是協定?IP不也是協定?嗯~~毛病倒是沒有,但是TCP/IP協定族是……額……不太好形容,它是網際網路中最為**經典的**、**事實的**通訊協定標準。
整個TCP/IP協定棧並不單純的代表TCP和IP,而是代表完整的網路通訊家族,由於它創造性的分層設計,所以也叫做**TCP/IP協定棧**。而TCP和IP則是整個家族中最早通過的標準。這些協定最早發源於美國國防部(縮寫為DoD)的ARPA網專案,因此也稱作DoD模型(DoD Model)。
我們來看張圖,整個DoD模型(下面我都這麼叫,因為字少~)是這樣的:
嗯~就這麼簡單,層數是由下往上計算的,分別是連結層、網路層、傳輸層以及應用層。所以,HTTP在哪一層呢?我相信大家都知道HTTP在應用層。
我們從下到上,依次來簡單說下各層負責的內容以及各層都大概涵蓋了哪些協定,為啥是大概涵蓋呢?額~因為整個TCP/IP協定族太大了,有幾十個甚至上百個協定,是不是有點誇張。
先來說說DoD模型的第一層,也就是連結層。負責在乙太網、WiFi 這樣的底層網路上傳送原始封包,工作在網路卡這個層次,使用 MAC 地址來標記網路上的裝置,所以有時候也叫 MAC 層。注意,這裡你尤其要注意下MAC這個詞。稍後我們捋線的時候會用到。
然後就是第二層,也就是網路層。IP協定就在這一層,到了這一層,我們就可以通過IP地址來識別目標主機,進行主機級別的目標識別了。
繼續,是第三層,也就是傳輸層。最為大家所熟知的TCP和UDP就在這一層,負責建立傳輸通道。
最後,就是我們的重中之重,第四層,也就是應用層,我們的HTTP就在這一層,由於前面幾層的基礎做的非常好,所以,在這一層除了HTTP協定負責傳輸超文字以外,還有超多的協定,比如我們稍微熟悉一點的HTTPS、DNS、POP、FTP等等等等,好多好多,我們暫時瞭解一下就可以了。
OK,DoD我們就先這樣。繼續,長路漫漫,唯賤作伴。
這個東西,有點孩子沒娘說來話長,我儘量長話短說。OSI模型是一種概念模型,也即開放式系統互聯模型。由國際標準化組織提出,一個試圖使各種計算機在世界範圍內互連為網路的標準框架。定義於ISO/IEC 7498-1。
為啥已經有了四層還有個七層呢?只有四層不行麼?主要是因為當時除了TCP/IP協定以外,還有很多其它協定,整個網際網路很混亂,有一種群雄逐鹿的感覺。所以這個時候國際化標準組織就大吼一聲,我是秦始皇,我要一統天下,你們都按照我的標準來。
但是,理想是美好的,可惜我不是秦始皇,所以一統天下的局面並沒有按照原本設想的那樣,於是秦始皇又不得不說,該模型僅供參考。
至於為什麼一統天下的局面沒有出現,導致我們現在還要多學一個模型,嗯~其實是因為裝置僵化。啥意思呢,就是實際中已經很多網路都按照DoD來用了,而且用的很好,不可能換成你的,代價太大。
那這OSI模型有啥意義呢?又沒一統天下,實際上也沒咋用,那說它幹啥。其實它有一個很重要的意義,對!就是參考。OSI模型補足了DoD模型只有純軟體以外的部分,並且形成了規範和標準,並且準確的規定了各層可以使用數位來編號。
故事說完了,我們來看看OSI這七層都是哪七層吧,雖然僅供參考,我們也得知道知道。
我們看圖說話噢,上面花裡胡哨的那三層就是多出來的三層,第一層是物理層,第五層是對談層,第六層是表示層。嗯,解釋解釋。
物理層也就是我們互連網路傳輸中所使用到的各種物理裝置,比如集線器,中繼器,網路卡啥的這些。
對談層呢,負責在資料傳輸中設定和維護計算機網路中兩臺計算機之間的通訊連線。說人話就是對談層負責在維護網路中的連線狀態,也就是保持對談和同步。比如視訊的圖片和聲音的同步。
表示層則會把資料轉換成雙方都可以理解的可以相容的格式。
DoD模型和OSI模型的對比,則是這樣的:
很好理解,我就不多說了。
現在,我們大致瞭解了網際網路絡模型是什麼樣的,接下來,我們來實際的看一看,一個封包到底是如何在這些模型中穿梭的。
一種思路是從最底層也就是物理層說起,層層向上遞進,這是從最小化網路的場景來聊網際網路絡協定。另外一種方式就是從應用層,層層向下,這種角度就是以最小封包的場景,我們下面就採用這種視角來窺一窺一個封包在網路中的流轉。
應用層是離我們最近的一層,這一層往往由安裝在系統上的應用程式來處理,這一層的協定有好多好多,也是在整個網際網路模型中所擁有最多協定的一層。
應用層協定包括我們所熟悉的HTTP、HTTPS、HTTP2、QUIC等,以及DNS、HTTPDNS、SSH,還有還有比如:
等等,當然還有很多很多。
其中有一部分我們會在本系列中粗略的講講,比如DNS、SSH啥的,剩下的與HTTP關聯性不大的,大家有興趣可以自行了解。
在應用層的階段,我們講HTTP嘛,所以就以HTTP為例,會形成一個封包,這個封包有哪些內容我們暫時可以不去管。反正就是一個包。
當應用層準備好了這個包以後,會把它發往**目標地址**。那麼第一個問題來了,當我在應用層準備好封包之後,我是直接傳送麼?還是要做什麼準備工作?
首先,在準備發起真正的HTTP封包傳遞之前,瀏覽器會率先把目標地址也就是一個域名傳送給DNS伺服器,換取目標IP。
然後我們就需要進行下一步,建立TCP通道,也就是通過三次握手建立TCP連結。
欸?感覺上面的描述有點問題,我在準備好包以後再去查DNS、建立TCP連結,那如果我TCP連結建立失敗了,那我HTTP的封包不是白處理了麼?
哇^v^,好吧,被你發現了,其實這麼說確實不太準確,更準確的應該是,在準備發起HTTP請求時,就會去做準備工作,等準備工作都做好了,才會去構建請求資訊,然後傳遞出去。
整個過程,大致如下圖所示:
上一小小節,我們停在了與伺服器建立連結的部分,這連結還沒建立完呢,你就不說話了。嗯。。。因為後面的事情其實與應用層的關係不大,所以我們拿到這一小節傳輸層來聊一聊。
傳輸層的協定數量就要比參照層少的多的多的,有點繞,哈哈哈。
傳輸層協定除了我們最熟悉的TCP與UDP之外,還有諸如:DCCP(資料擁塞控制協定)、SCTP(流控制傳輸協定)、RSVP(資源預留協定)等協定。當然這些協定,我們瞭解下就好。重點還是在TCP和UDP。
TCP大名叫做傳輸控制協定,英文名叫做Transmission Control Protocol,TCP是傳輸控制協定的英文名的縮寫。它是一種面向連線的、可靠的、基於位元組流的傳輸層通訊協定。
可靠和基於位元組流都比較好理解,面向連線是怎麼個意思?我聽說過物件導向,程式導向,怎麼還有面向連線?怎麼個面向法?我在大馬路上看車來車往算是面向連線麼?(不好意思,一不小心點了一下題)。
假如你在大馬路上看車跑來跑去,那如果這個車到了某個目的地又返回到出發點,來來回回,來來回回,那就算是面向連線,如果這車從你面前過去,不回來了,跑沒影了,那就不算。
好啦,通過一個小栗子,我們大概理解了什麼是面向連線,簡單說就是有來有回唄。那麼有來無回呢?巧了,就是UDP協定。
UDP的全稱是使用者資料包協定,英文名叫做**U**ser **D**atagram **P**rotocol,它是一個簡單的面向封包的協定,換句話說,就是我只負責傳輸封包,在傳輸的過程中跑丟了,那就不歸我管了。
簡單介紹了點概念哈,我們繼續上一小節中的圖,在真正傳送HTTP封包之前,最重要的就是要建立TCP連線,但是,要注意,我們建立TCP連線時,實際上並不關應用層什麼事,只是應用層需要這個連線,所以才告知TCP去建立傳輸的通道。也就是說,沒有應用層咯?嗯,**簡單說就是,網路傳輸中,可以有下層,沒上層,但是不可能有上層,沒下層。** 這個一定要注意。
那麼建立通道的第一步,大家一定耳熟能詳,就是TCP的三次握手。欸?為啥是三次,不是一次,不是三十次?嗯,因為三次,是雙方可以最小確認彼此的次數。再解釋下,也就是說,是使用者端與伺服器各自都可以收到一個來回的資訊,還記得面向連線不?
我們來看看三次握手是咋握的。
欸?你這不對啊,你這哪有握手的過程,"與伺服器建立連線"這幾個字,就代表了三次握手的內容。當然,真正的三次握手是這樣的:
我們來看上圖哈,裡面還有點東西的。在最開始的時候,使用者端和伺服器都處於關閉的狀態,然後伺服器會處於監聽的狀態。當用戶端發起第一次握手連線請求時,使用者端會設定當前的狀態為SYN_SEND的狀態,注意這裡傳送的seq=x,**這個x並不是一個亂數,而是當前的TCP包的序號**,注意這一點,我們描述完整個過程會在說說這個序號。
伺服器收到這個訊息後,就會把x+1作為ack結果,也就是返回的訊息,在返回的訊息中還給回用戶端一個seq為y,同樣的,這個y也是一個序號。那麼此時伺服器就處於SYN_RCVD也就是接收到了訊息的狀態。
繼續,當用戶端收到了伺服器的回信後,知道這個連線已經通知伺服器建立了,於是使用者端把伺服器端傳過來的seq再加1作為ack應答給伺服器,並且設定當前狀態為ESTABLISHED,也就是建交成功,當伺服器收到結果,一計算seq和ack沒問題,那麼伺服器也設定為建交成功,可以傳遞資料了。
這就是三次握手。那為啥要有seq和ack呢?我直接喊一聲,你答應一聲,然後我再喊一聲不就完事了麼,非要加一加一干啥啊。
嗯~這是為了記錄當前的包是從哪開始的,你想像一下,在馬路上跑的車有很多,有的車可能跑丟了,或者跑到別的國家了,壓根不回來了,你咋整?所以TCP每發一個包都會記錄一下,也就是遞增1,你的seq和ack是要屬於本次請求要求遞增的包序號才算是屬於本次建交的應答和響應。
那麼接下來就要開始傳輸資料了,應用層把HTTP封包都準備好了,已經迫不及待要出發了,那麼到了TCP這一層後,TCP會往這個包里加點東西:
TCP會在應用層的HTTP包的基礎上再加上TCP頭,這裡麵包含了源埠號和目標埠號,有了埠號,我們就可以確定目標埠號從而找到目標應用,當資訊返回的時候還會用到源埠號,這個我們後面再說。
網路層提供路由和定址的能力,由於在TCP/IP協定族中,網路層的能力由IP協定來實現,所以又稱為網路層又可以叫做IP層。
但是網路層可不僅僅只有IP協定,還有比如ICMP(網際網路控制訊息協定)、IGMP(網際網路組管理協定)、BGP(邊界閘道器協定)、RIP(路由資訊協定)、OSPF(開放式最短路徑優先協定)、RARP(逆地址解析協定)等等。我們簡單瞭解下就可了。
還是說回IP協定,IP的主要任務其實很簡單,就是根據源主機和目的主機的地址來傳遞資料。當封包到了三層之後,就會把源主機和目的主機的IP地址再加入到封包中傳給第二層。
而這一層的IP頭,形象的比喻一下的話,就像是我們所在小區的樓牌號,有了樓牌號我們就能找到具體的人。在網際網路中,有了IP才可以找到具體是哪一臺機器。
當然,我們僅僅只知道樓牌號還不行,還得知道是哪個省市區的,北京的某某一小區和南京的某某小區,極大的可能會有同一個樓牌號,這肯定不行。
所以我們就得來到下一層,也就是鏈路層來解決省市區的問題了。
鏈路層的主要作用是在區域網中專職處理媒介的爭用與衝突問題。換句話說,就是我到了這個小區,要把快遞給誰的問題。而鏈路層的協定其實也不少,其中還有不少大家耳熟能詳的協定,比如GPRS,Wi-Fi都是鏈路層協定,當然還有很多,有興趣大家可以自行了解。
鏈路層也可以叫做MAC層,MAC的全稱叫做Medium Access Control,媒體存取控制,它要控制啥呢?其實就是控制資料傳送的順序和目標,誰先發,誰後發,誰來接收誰來傳送的問題,不能搞亂了。
當資料傳遞到MAC層後,MAC層會再加上一個MAC頭,這裡有源MAC地址和目標MAC地址:
按理來說啊,到這後面就是一片坦途的到達目標伺服器了,但是封包的旅程其實才剛剛開始。
當封包出了閘道器之後,也就是出了我們的小區,你的小區會告訴這個封包下一個小區要去哪,一個小區一個小區的跳啊跳,最終才會到達我們的目的地,那你可能會問,我直接讓我的小區告訴我直接要到哪個小區不行麼,為啥只能一個一個的跳來跳去的呢,嗯……因為全世界的小區數量太大,你的小區記不了那麼多。
到了物理層,實際上就脫離了軟體層面,是實實在在的可以接觸到的電子裝置了,比如光纖,同軸電纜,雙絞線等等,嗯……它們是幹啥的我都不知道,我也不告訴你。
到了物理層後,資料最終會到達伺服器,然後再反過來經歷剛才的階段,層層解開封包,獲取當前層所需要的資訊,最終定位到目標應用的埠號,此時,我們包的旅程才算是真正的完成了。
這張圖並不完全,明顯缺失了很大一塊,但是我相信你一定知道那缺失的部分有哪些內容,也當作是留給你的作業吧~
其實到這裡本篇就算是完事了,但是完事的有點突然,其實在描述上面的整個封包流轉的過程中,越到底層我描述的就越少,其實我刻意省略了很多關於TCP、IP以及MAC的重要內容,但是這篇系列畢竟不是講網際網路絡的,大家知道它在空間上經歷了哪些部分即可,如果有興趣,大家可以自行查詢資料學習,我猜你不會找,哈哈哈哈
資料傳輸完了之後,TCP還需要做一點事情,就是通道建立了,但是當我不需要的時候,我想把通道關閉,不然一直監聽著有沒有訊息給我實在是太累了。
當TCP關閉通道的時候,需要通過四次揮手來確認,它是這樣揮手的:
我們解釋完這張圖,本章就完事啦。
我們簡單解釋下這張圖,當用戶端傳送一個「我不玩了」的訊息後,就會進入到FIN_WAIT_1的狀態,等待後續的伺服器反饋,當伺服器收到訊息後,就會在之前的基礎上給包序號加+1返回給使用者端,那麼此時伺服器就進入到了CLOSED_WAIT的待關閉狀態。
我們稍微跑題一下,在學習了三次握手,和上面四次揮手的圖示後,你發現一個問題沒有,就是所有的應答都是在請求的基礎包序號上+1。換種理解方式就是+1的序號都是作為應答出現的包。
我們繼續上面的話題,當用戶端收到了伺服器的第一次響應應答後,會進入到FIN_WAIT_2的狀態,為啥這裡使用者端要等伺服器再傳送一個包呢?假如伺服器還有未處理完的資料要給你咋整?你不是還得接收,所以要等伺服器的資料都處理完畢了,告訴使用者端,我這邊也可以不玩了才行。
於是,當伺服器也結束了自己的任務的時候,就把包發給使用者端,使用者端進入TIME_WAIT的狀態。當伺服器收到第二次使用者端的應答後,就直接關閉了。
最後,TCP還要求使用者端還是要持續的監聽一段時間,這個時間就是報文最大生存時間,等了一段時間後,就進入關閉的狀態了。
我們看哈,其實整個四次揮手,一次是由使用者端發起,一次伺服器應答,一次是由伺服器發起,使用者端應答,最後,使用者端再等待一段時間。才最終結束整個揮手過程。
那他為什麼不可以像三次握手那樣,請求,響應,響應響應,三個步驟就可以了呢。這裡有一個核心就是,建立連線時,雙方都處於空閒狀態,沒有正在執行的程式,而關閉時,需要確定雙方的程式都結束才可以。所以再四次揮手的由伺服器發起的請求的過程中,就是為了等待伺服器的任務跑完。
我們稍微回顧下我們本章都學習了什麼。
由於篇幅所限,文章很多內容並未詳細涉及,因為其實本章所講內容如果擴大一點,就可以叫做《網路基礎》,嗯,可以寫好幾本書。如果你對此有興趣並且有時間,我還是十分建議去深入學習一下的。
最後,本人能力有限,若在閱讀過程中發現謬誤,還望不吝指教。非常感謝~~