當把網址輸入到瀏覽器地址欄,按下回車鍵後,一段浩瀚的互聯網歷險就開始了。html
本文將結合我的所學並參考《網絡是怎樣鏈接的》一書,簡要介紹從輸入網址到網頁最終呈現這個過程當中涉及的諸多軟硬件的原理及工做方式。git
目錄es6
零、URL網址github
1、應用層(瀏覽器、HTTP協議)web
(一)Web瀏覽器的初步工做chrome
(二)調用操做系統Socket庫進行DNS查詢segmentfault
(三)發送HTTP請求瀏覽器
2、傳輸層(TCP、UDP)緩存
(四)程序對程序的鏈接服務器
3、網絡層(IP)
(五)確立主機對主機的鏈接
4、連接層(網卡、以太網)
(六)在以太網上傳輸
5、實體層(路由器、調制解調器、網關等)
(七)光信號/電信號經各類設備傳輸
(八)服務器響應請求
參考資料
網址一般是一個URL
,即「統一資源定位符」
,是萬維網的創造者——蒂姆·伯納斯·李的發明之一。
就像現實生活中的地址同樣,它的用處是規範地在互聯網上標識資源的地址。
統一資源定位符URL的標準格式以下:
協議類型:[//服務器地址[:端口號]][/資源層級UNIX文件路徑]文件名[?查詢][#片斷ID]
其中的協議類型://
,端口號
,文件名
都可在某些狀況下省略。
例如:
協議類型://
。而服務器地址
出於便於人類記憶的目的,一般會是一個具備語義化的域名
,而不是更加精確的標識一臺計算機在網絡世界中位置的IP地址
或MAC地址
。
瞭解完了URL,就該主角們紛紛亮相了。
千里之行始於足下。
首先,瀏覽器會解析出所輸入的URL之中包含的協議,服務器地址,路徑,端口號等信息,並根據這些信息決定向誰請求什麼資源。
可是由於URL中的服務器地址一般是一串具備必定語義的英文字符:域名
,這個地址不夠精確,它可能表明不止一臺服務器,更沒法指明服務器的具體位置,瀏覽器或者說計算機並不能依靠這個地址在浩瀚的互聯網世界中精確地找到目標服務器。
因此還須要進一步藉助DNS查詢
獲得IP地址
才能定位目標服務器的位置。
在進行DNS查詢獲取IP地址以前,瀏覽器會先在內部的DNS緩存中查找是否存在所查詢域名的IP地址。
Chrome瀏覽器能夠經過訪問
chrome://net-internals/#dns
查看瀏覽器的DNS緩存狀況
若是沒有經過瀏覽器的DNS緩存查詢到IP,還會進一步藉助操做系統查詢本地hosts文件看是否有可用的DNS緩存記錄
Windows 系統一般位於C:WindowsSystem32driversetc 目錄下
若是都沒有找到目標域名的地址,就要向DNS服務器請求查詢了。
瀏覽器並不能直接找到DNS服務器進行查詢,須要操做系統中Socket
庫的幫助。
Socket
庫是操做系統提供的一組調用操做系統網絡功能的程序組件集合,在計算機網絡之中有很是重要的地位,後續咱們還會介紹和它相關的內容。
DNS
是Domain Name System
即域名系統
的縮寫。這個系統的主要功能就是根據域名
獲取IP
地址。
DNS服務器
是域名系統
的具體組成部分,其數量有不少不少,分佈在現實世界中的不一樣位置和網絡世界中的不一樣層次,用於響應不一樣地區、不一樣層次域名的查詢請求。
DNS服務器的地址須要記錄在本機之中,Windows系統中能夠在控制面板\網絡和 Internet \網絡鏈接
中右鍵進入任意一個鏈接的屬性,雙擊Internet協議版本4(TCP/IPV4)
查看。
在這個面板中能夠看到設置以下四項的輸入框:
值得一提的是,由於這四項內容比較複雜,不便於普通用戶設置,因此我的電腦中這幾項一般都會被設置爲自動得到
,使用動態分配IP
。
這樣,當計算機連入網絡時,就會利用DHCP協議
向負責管理本區域網絡全部IP地址的DHCP服務器動態地請求一個IP地址。
調用Socket
庫發送DNS查詢請求時,會向本機中記錄的DNS服務器IP地址發送請求,接收到DNS查詢請求的DNS服務器會優先在本身緩存的路由表
中查詢目標域名對應的服務器IP地址。
若是在緩存之中沒有找到,DNS服務器則會根據域名的層次分級逐層查詢。
例如,查詢 https://github.com/JuniorTour 這個域名對應的 IP 時,DNS服務器會逐層向根域名 (.root) 服務器、頂級域名 ( .com ) 服務器、次級域名 ( .github ) 服務器發送查詢請求,自頂向下,直到找到域名對應的IP地址。
順帶一提,次級域名 ( .github ) 之下,還有一層能夠由用戶本身分配的三級域名。github.com
這個域名其實是省略了www
這個三級域名的寫法。
知道了URL對應的IP地址後,就能夠向這個地址發送HTTP請求,請求所需的網絡資源了。
瀏覽器瀏覽網頁用的是屬於應用層的HTTP協議
,若是想要獲取一個網頁,就須要向HTTP服務器發送HTTP請求
,在響應的數據中獲取網頁數據。
一般來講,一個HTTP請求大概長這樣子:
GET /JuniorTour HTTP/1.1 Host: github.com User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9 Accept-Encoding: gzip, deflate Accept-Language: zh-CN,zh;q=0.9,en;q=0.8 Cookie: authorstyle=no
它主要由如下幾部分組成:
<request-line> 請求行 <headers> 請求頭 <blank line> 空格 <request-body> 請求數據
瀏覽器在掌握了HTTP服務器的IP地址以及文件名、Cookie、用戶代理(User-Agent)等發送請求所需的信息後,就會根據這些信息生成相應的HTTP請求,轉交給協議棧
,由它來具體執行發送請求。
協議棧是操做系統中的網絡控制軟件,主要由TCP模塊
、UDP模塊
和IP模塊
組成,分別負責用不一樣的協議收發數據。
在HTTP請求轉交給協議棧
發送以前,協議棧或者說是客戶端主機首先須要鏈接上服務器。
這個創建鏈接的過程就是著名的三次握手
,遵循的是TCP協議
。
其大體過程以下:
第一次握手:創建鏈接請求,客戶端發送請求報文,將TCP頭部的SYN字段標爲1,表示鏈接。第二次握手:鏈接創建中,服務器收到客戶端的創建鏈接請求報文後,會發送響應報文,也會將TCP頭部的SYN字段和ACK字段標爲1。
第三次握手:鏈接創建,客戶端收到服務器的確認鏈接響應後,會再次向服務器發送一個ACK字段爲1的TCP報文,發送完這個報文後,客戶端和服務器都會進入「鏈接已創建」狀態,隨時準備收發報文。
打一個形象的比喻就是這樣的:
客戶端告訴服務器:我們要開始鏈接了哦~服務器聽到後,回覆客戶端說:我知道了!
客戶端和服務器都確認對方收到消息後就會知道:行了,鏈接創建了~~
收發數據結束後,還須要斷開鏈接,也就是四次揮手
。
以Web爲例,服務器會在向瀏覽器返回響應信息後,由服務器一方發起斷開鏈接。其大體過程以下:
第一次揮手:服務器發送斷開鏈接請求,服務器完成數據響應後,會經過服務器的協議棧向客戶端發送一個FIN字段爲1的TCP報文。第二次揮手:客戶端確認斷開請求,客戶端的協議棧接收到服務器的斷開鏈接請求報文後,會向服務器返回一個ACK字段爲1的響應報文,表示已收到斷開鏈接請求。
這時客戶端的應用程序就會來讀取這次響應的數據,客戶端的應用程序獲得了數據後,也會再向服務器執行一次斷開鏈接操做。
第三次揮手:客戶端發送斷開鏈接請求,客戶端向服務器發送一個FIN字段爲1的TCP報文。
第四次揮手:服務器確認斷開鏈接,收到客戶端發來的斷開鏈接請求後,服務器會相應地返回一個ACK字段爲1的響應報文,表示已收到斷開鏈接請求。
仍是用一個更形象的比喻來描述一次:
服務器發送完數據後對客戶端說:數據發完了哦!客戶端得知後回覆說:行,我知道了。
客戶端檢查、儲存數據後,又對服務器說:確實都發完了,我們斷開鏈接吧!
服務器聽到後說:好的,我知道了,斷開鏈接吧。
從上述過程也能夠看出:TCP協議
是一個很是重視可靠性
的協議,鏈接的創建和斷開都經歷了再三的重複和確認,有效地保證了網絡數據傳輸的可靠性
。
發送HTTP請求到一個服務器來獲取響應,還有一個問題沒有解決。
那就是服務器主機收到HTTP請求後如何判斷這個請求是發給這臺服務器主機上哪個程序的,一臺服務器主機上可能會運行着多個服務器或程序,該如何判斷這個請求是發給哪個服務器的呢?
同理,當響應傳回客戶端的我的計算機,又該如何判斷這個響應是發給哪個應用程序,是Chrome,仍是微信呢?
這就須要另外一個指標來標識一臺計算機上運行的不一樣程序。
這個指標就是端口。
端口(port)
,實際上是每個使用網卡
的程序的編號。
不一樣的程序佔用不一樣的端口,每一個數據包都指定發送到主機的特定端口,不一樣的程序就能依據端口號收到本身所須要的數據。
在兩臺主機創建鏈接以後,創建端口對端口的通訊,依據端口號肯定數據究竟是發送給這臺電腦中的哪個程序,這就是傳輸層
的主要做用。
爲了將HTTP請求發送給服務器主機的指定程序,須要委託協議棧中的TCP模塊對HTTP請求的數據包進行封裝,加上帶有端口信息的TCP頭部。
這裏的端口號也來自一開始在瀏覽器中輸入的URL,一般URL中的端口號能夠省略不寫,此時就會把事先約定好的HTTP默認端口號: 80或HTTPS默認端口號: 443, 看成目標端口號。
若是指定了端口號,例如:https://github.com:443/JuniorTour ,則會相應地根據指定的端口號附加在HTTP請求上,生成TCP數據包
。
大多數應用程序都使用TCP協議來收發數據的,可是有些程序也會使用更簡單、更高效的UDP協議
。
例如向DNS服務器查詢IP用的就是UDP協議。
UDP協議和TCP協議的關鍵不一樣點在於,UDP協議爲了追求高效率,並不會在收發數據的先後進行確認,也就是前面說的三握四揮
,這樣的實現相比TCP協議收發數據會更高效。
可是相應的,收發數據的可靠性就會有必定打折,傳輸過程當中發生丟失部分數據包的可能性會更大,即所謂的丟包
。
也正是由於效率更高、可靠性較差這兩個特色,讓UDP協議在短數據收發、多媒體數據收發上有獨特的應用。
前面的工做都完成後,就要在兩臺主機之間創建鏈接了。
爲了實現這一點須要用到明確標識兩臺主機的標誌,就是以前曾屢次說起的IP地址
。
IP地址的規範主要有兩個版本,即 IPv4 和 IPv6 ,他們分別規定了不一樣長度的IP地址。
以 IPv4 爲例,IP地址由32個二進制位組成,例如:11000000.10100010.00000001.00000001,通常習慣用十進制表示,例如:192.168.1.1。
IP地址的做用除了標識一臺計算機在網絡世界中的地址外,還有判斷兩臺計算機是否屬於同一個子網絡
的功能,這項功能的實現須要子網掩碼
的輔助。
子網掩碼也是一段32位的二進制數,例如:11111111.11111111.11111111.00000000,用十進制表示即爲:255.255.255.0,其表明網絡部分的全爲1,表明主機部分的全爲0。
子網掩碼的用法是分別和兩個IP地址作與運算
,若是得出的結果相同,則能夠斷定兩個IP屬於同一個子網絡。
這兩項內容的設置和查看方式已經在前文的DNS一節有所介紹。
爲了在兩臺主機之間創建鏈接,就須要在數據包中添加帶有IP地址的IP頭部
,並進一步向外傳輸。
IP模塊還會作一件很是重要的事情,就是經過ARP(Address Resolution Protocol,地址解析協議)
,以廣播的形式向同一以太網內的全部設備提問:「 XXX.XXX 這個 IP 地址是誰的?請把你的MAC地址告訴我」,以後就會有同一子網內的其餘設備(一般是路由器)回覆IP 地址
對應的MAC地址
。
另外ARP也是有緩存的,會緩存查詢結果。
獲取到MAC地址以後,IP模塊就會再給數據包加上一個帶有MAC地址信息的MAC頭部
並轉交給網卡傳輸。
IP模塊的工做完成後,生成的網絡包仍是不能直接發送給對方,由於此時的網絡包還只是內存中的一串數字信號
,要在網線上傳輸,還須要把這些數字轉換爲電信號或光信號。這個工做是由網卡及其驅動程序完成的。
網卡
是計算機上常見的硬件之一,主要功能是信號和數據的編解碼、數據包的收發等。
網卡內部有複雜的各類構造,網卡做爲一個硬件,和操做它的軟件——網卡驅動之間也有多種多樣的交互,但在此爲了簡化這一過程,咱們只瞭解最關鍵的一小部分細節。
網卡的ROM(只讀存儲器)中保存着全世界惟一的MAC地址
,這個地址是生產網卡時寫入的。
以太網上數據包的發送和接收地址都是MAC地址
,網卡會將以前IP模塊生成的數據包按照必定的規則轉換爲可在現實世界網線中傳輸的信號,經過網線發送出去。
至此,客戶端的工做已經完成,數據包進入到了以太網之中進一步傳輸。
在這一章的開頭,我想先介紹四個容易混淆的概念:互聯網、因特網、以太網和萬維網。
Internet
,互聯網是意譯,因特網是音譯,二者在今天都是泛指全球範圍內由海量網絡相互鏈接而成的龐大網絡
。早先,大寫開頭的Internet
專指IP協議架設而成的網絡,小寫開頭的internet
則泛指其餘各類網絡,小寫表明的意義包含大寫。而今天,在各類網絡中,以IP協議架設而成的網絡已經佔據統治地位,是現代人類生活的一部分。小寫開頭的internet
的泛指含義已經沒有意義,因此,今天這兩個詞指的是同一個事物,即全球範圍內由海量網絡相互鏈接而成的龐大網絡
。World Wide Web
簡稱Web
,是架構在互聯網之上的一項服務
,由英國科學家蒂姆·伯納斯-李於1989年發明,這項服務的核心由統一資源標識符(URI)、超文本傳送協議(HTTP)、超文本標記語言(HTML)構成,並藉助瀏覽器等工具爲其用戶提供各類信息和資源。Ethernet
是一項局域網通訊技術
,它所涵蓋的內容十分豐富,其技術標準是著名的IEEE 802.3標準
,某種程度上 IEEE 802.3 就是以太網,其規定了網絡鏈接的規範和電子信號的分組模式等諸多內容。咱們要了解的重點是以太網,以太網具體的數據傳輸方式是:廣播
,即向整個網絡上的每一臺設備都發送信號,就像是在一間屋子裏喊話同樣,一我的喊的話,同一間屋子的全部人都能聽到。可是爲了明確指出這句話是說給誰的,還須要加上存儲在網卡之中標識網絡內的每個節點的MAC地址,就像喊話的時候帶上了人名同樣。
以太網中以廣播的形式向一個MAC地址傳輸數據的方式有很大的弊端,互聯網是由許許多多子網絡構成的龐大網絡,當兩臺設備不在同一個子網絡之中,卻仍採用廣播形式時,不只會有效率上的巨大浪費,也不能準確地傳輸到目的地。
針對這個弊端,在以太網中傳輸的數據會依據IP地址和子網掩碼判斷是否屬於同一個子網絡。
若是和目標主機不在同一個子網絡之中的,會像某一個路由
發送數據,由它代理轉發到其餘子網絡之中。相反,當屬於同一個子網絡時,則仍然採用廣播的方式傳輸數據。
數據被處理成光信號/電信號後,會通過網線、路由器、調制解調器、網關等各類設備的處理轉發。
這一部分已經進入了網絡硬件的領域,爲了保持文章篇幅,不作過多描述。
經歷了萬水千山、長途跋涉,最初的請求終於到達了目標服務器主機。
服務器主機獲得數據包後,會通過網卡、網卡驅動程序、服務器協議棧的層層解析,最終將請求交給服務器處理。服務器處理後,會生成相應的HTTP響應
,再將數據包返回給客戶端,這個過程幾乎就是上文所述的逆向操做。
客戶端的瀏覽器獲得了服務器返回的HTTP響應
後,將其中的內容解析出來,渲染、呈如今了咱們的眼前。
回過頭來再看,這幾章對應的分別就是互聯網的五層模型:
《網絡是怎樣鏈接的》-【日】戶根勤 著, 周自恆 譯
[簡析TCP協議中的三次握手和四次揮手](https://segmentfault.com/a/11...
有任何想法、建議,歡迎在評論區留言或來GitHub 和我交流:https://github.com/JuniorTour/ ,我會盡快回復的