記錄本身第一次學計算機網路基礎後的總結,但願各位大佬可以幫助小老弟糾正錯誤,以及對知識點進行補充。php
以一道經典面試題 輸入URL後發生了什麼 爲核心,開始了我學習計算機網絡之旅。本篇文章知識對部分過程進行一個總結概述,其中遇到的有些知識點因爲太深刻沒有學習到,通過後續學習以後會對本文進行補充整理。前端
但願本文可以幫各位大佬回顧一下計網的基礎知識點,同時若是你是和我同樣在前端路上剛開始出發,能夠點贊+關注,以後會陸續分享我整理好的知識體系。 面試
尾部有彩蛋哈~分爲兩個大部分,一部分是生成HTTP請求,另一部分是瀏覽器委託協議棧進行通訊。瀏覽器
大致分爲以下步驟:緩存
因爲知識點有點多,請各位大佬細聽小弟娓娓道來。服務器
咱們的探索之旅從在瀏覽器中輸入網址開始,在介紹瀏覽器的工做方式以前,讓咱們先來介紹一下網址,準確來講應該叫URL。網絡
實際上除了「http:」,網址還能夠以其餘一些文字開頭,例如 「ftp:」 「file:」 「mailto:」等。之因此有各類各樣的URL,是由於一般瀏覽器是用來訪問Web服務器的,但它也能夠用來在FTP服務器上下載和上傳文件,同時也具有電子郵件客戶端的功能。併發
能夠說瀏覽器是一個具有多種客戶端功能的綜合性客戶端軟件。socket
所以它須要一些東西來判斷應該使用其中哪一種功能來訪問相應的數據,而各類不一樣的URL就是用來肯定網址所使用的不一樣方法,一般咱們稱之爲協議類型函數
因此說瀏覽器要作的第一步工做就是對URL進行解析
解析完URL以後,咱們就知道應該要訪問的目標在哪裏了。接下來,瀏覽器會使用HTTP協議來訪問Web服務器,在此以前咱們先複習一下HTTP協議。
HTTP協議定義了客戶端和服務器之間交互的消息內容和步驟。
首先,客戶端會向服務器發送請求消息,請求消息中包含的內容是對誰和進行何種操做兩個部分。
除此之外,HTTP消息中還有一些用來表示附加信息的頭字段。客戶端向Web服務器發送數據時,會先發送頭部字段,而後再發送數據。
收到請求消息以後,Web服務器會對其中的內容進行解析,根據這些要求來完成本身的工做,而後將結果存放在響應消息中。
在響應消息的開頭有一個 狀態碼 和 解釋信息,它用來表示操做的執行結果。
後面就是頭字段和網頁數據。響應消息會被髮送回客戶端,當收到以後,瀏覽器會從消息中讀出所需的數據並顯示渲染。到這裏,HTTP的整個工做就以完成。
其中最經常使用的一個是GET方法,通常當咱們訪問Web服務器獲取網頁數據時,使用的就是GET方法。
另一個就是POST方法,咱們在表單中填寫數據並將其發送給Web服務器時就會使用這個POST方法,當咱們在網上商城填寫收貨地址和姓名,或者是在網上填寫問卷時,都會遇到帶有輸入框的網頁,而這些能夠輸入信息的部分就是表單。
使用POST方法時,URI會指向Web服務器中運行的一個應用程序的文件名,典型的例子包括「index.cgi」「index.php」等。而後,在請求消息中,除了方法和URI以外,還要加上傳遞給應用程序和腳本的數據,也就是表單中填入的數據。當服務器收到消息後,Web服務器會將請求消息中的數據發送給URI指定的應用程序。最後,Web服務器從應用程序接收輸出的結果,會將它存放到響應消息中並返回給客戶端。
以後會有對HTTP進行詳細整理,在此不作贅述。
理解了HTTP的基本知識以後,咱們回到對瀏覽器自己的探索中。對URL進行解析以後,瀏覽器肯定了Web服務器和文件名,接下來就是根據這些信息來生成HTTP請求消息。
首先,請求消息的第一行稱爲 請求行。這裏的重點是開頭的方法,能夠告訴Web服務器它應該進行怎樣的操做。第一行的末尾須要寫上HTTP的版本號,這是爲了表示該消息是基於哪一個版本的HTTP 規格編寫的。
第二行開始爲消息頭。裏面存放了除了請求行外的額外詳細信息。如日期、客戶端支持的數據類型、語言、壓縮格式、客戶端和服務器的軟件名稱和版本、數據有效期和最後更新時間等。
寫完消息頭以後,還須要添加一個徹底沒有內容的空行,而後寫上須要發送的數據。這部分稱之爲消息體。消息體結束以後,整個消息也就隨之結束。
當咱們將上述請求消息發送出去以後,Web服務器會返回響應消息,響應消息的格式以及基本思路和請求消息是相同的,差異只在第一行上。
在響應消息中,第一行的內容爲狀態碼和響應短語,用來表示請求的執行結果是成功仍是出錯。狀態碼和響應短語表示的內容一致,但它們的用途不一樣。狀態碼是一個數字,它主要用來向程序告知執行的結果,響應短語則是一段文字,用來向人們告知執行的結果。
生成HTTP消息以後,接下來咱們須要委託操做系統將消息發送給Web服務器。首先咱們要查詢網址中服務器域名對應的IP地址。(通訊必需要提供IP地址),簡單回顧一下IP地址。
互聯網和公司內部的局域網都是基於TCP/IP的思路來設計的,因此咱們先來了解 TCP/IP的基本思路。
TCP/IP的結構如圖所示,就是由一些小的子網,經過路由器鏈接成大的網絡。這些子網能夠當作使用集線器鏈接起來的幾臺計算機,咱們將他們當作一個單位,稱之爲 子網。經過路由器鏈接起來造成一個 網絡。在網絡中,全部的設備都會被分配一個地址。這個地址就至關於現實中某條路上 的「××號××室」。其中「號」對應的號碼是分配給整個子網的,而「室」對應的號碼是分配給子網中的計算機的,這就是網絡中的地址。「號」對應的號碼稱爲網絡號,「室」對應的號碼稱爲主機號,這個地址的總體稱爲IP地址。
經過IP地址咱們能夠判斷出訪問對象服務器的位置,從而將消息發送到服務器。 前面這些就是TCP/IP中IP地址的基本思路。瞭解以後讓咱們再來看一下實際的IP地址。
實際的IP地址是一串32比特的數字,按照8比特(1字節)爲一組分紅4組,分別用十進制表示而後再用圓點隔開。這就是咱們日常常常見到的IP地址格式,但僅憑這些咱們沒法區分哪部分是網絡號,哪部分是主機號。在IP地址的規則中,網絡號和主機號連起來總共是32比特,但這兩部分 的具體結構是不固定的。
在組建網絡時,用戶能夠自行決定它們之間的分配關係, 所以,咱們還須要另外的附加信息來表示IP地址的內部結構。 這一附加信息稱爲子網掩碼。
子網掩碼的格式如圖所示,是一串與IP地址長度相同的32比特數字,其左邊一半都是1,右邊一半都是0。其中,子網掩碼爲1的部分表示網絡號,子網掩碼爲0的部分表示主機號。將子網掩碼按照和IP地址同樣的方式以每8比特爲單位用圓點分組後寫在IP地址的右側,這就是上圖(b)的方法。
TCP/IP網絡是經過IP地址來肯定通訊對象的,不知道IP地址就沒法將消息發送給對方,因此在委託操做系統發送消息時,必需要先查詢好對方的IP地址。
既然如此,那麼在網址中不寫服務器的名字,直接寫IP地址不就行了嗎?實際上,若是用IP地址來代替服務器名稱也是可以正常工做的。然而,就像你很難記住電話號碼同樣,要記住一串由數字組成的IP地址也很是困難。所以,相比IP地址來講,網址中仍是使用服務器名稱比較好記憶。
既然如此,那乾脆不要用IP地址而是用名稱來肯定通訊對象不就行了嗎?
從運行效率上來看,這並不能算是一個好主意。互聯網中存在無數的路由器, 它們之間相互配合,根據IP地址來判斷應該把數據傳送到什麼地方。,使用IP地 址只須要處理4字節的數字,而域名則須要處理幾十個到255個字節的字符,這增長 了路由器的負擔,傳送數據也會花費更長的時間。同時路由器的速度是有極限的,而互聯網內部流動的數據量已然讓路由器疲於應付了,所以咱們不該該再採用效率更低的設計。
因而,如今咱們使用的方案是讓人來使用名稱,讓路由器來使用IP地址。爲了填補二者之間的障礙,DNS服務孕育而生。
向DNS服務器發出查詢,並接收DNS服務器返回的響應消息。對於DNS服務器,咱們的計算機上必定有相應的DNS客戶端,而至關於DNS客戶端的部分稱爲DNS解析器,經過DNS查詢IP地址的操做稱爲域名解析。
解析器其實是一段程序,它包含在操做系統的Socket庫中,在介紹解析器以前,咱們先來簡單瞭解一下Socket庫。
Socket庫其中包含的程序組件可讓其餘的應用程序調用操做系統的網絡功能,而解析器就是這 個庫中的其中一種程序組件。解析器的用法很是簡單,Socket庫中的程序都是標準組件,只要從應用程序中進行調用就能夠了。調用解析器後,解析器會向DNS服務器發送查詢消息,而後DNS服務器會返回響應消息。響應消息中包含查詢到的IP地址,解析器會取出IP地址,並將其寫入瀏覽器指定的內存地址中。只要運行圖中的這一行程序,就能夠完成IP地址的查詢。接下來,瀏覽器在向Web服務器發送消息時,只 要從該內存地址取出IP地址,並將它與HTTP請求消息一塊兒交給操做系統就能夠了。
瀏覽器調用解析器時,程序的控制流程就會轉移到解析器的內部。
經過讓多個程序按順序執行操做,數據就被髮送出去了。順帶一提,向DNS服務器發送消息時,咱們固然也須要知道DNS服務器的IP地址。只不過這個IP地址是做爲TCP/IP的一個設置項目事先設置好的,不須要再去查詢了。 不一樣的操做系統中TCP/IP的設置方法也有差別,解析器會根據設置的DNS服務器IP地址來發送消息。上述圖片是查找www.google.com的IP地址過程。
首先在本地域名服務器中查詢IP地址,若是沒有找到的狀況下,本地域名服務器會向根域名服務器發送一個請求,若是根域名服務器也不存在該域名時,本地域名會向com頂級域名服務器發送一個請求,依次類推下去。直到最後本地域名服務器獲得google的IP地址並把它緩存到本地,供下次查詢使用。
從上述過程當中,能夠看出網址的解析是一個從右向左的過程: com -> google.com -> www.google.com。
可是你是否發現少了點什麼,根域名服務器的解析過程呢?事實上,真正的網址是www.google.com.,並非我多打了一個.,這個.對應的就是根域名服務器,默認狀況下全部的網址的最後一位都是.,既然是默認狀況下,爲了方便用戶,一般都會省略,瀏覽器在請求DNS的時候會自動加上,全部網址真正的解析過程爲: . -> .com -> google.com. -> www.google.com.。
有時候並不須要從最上級的根域開始查找,由於DNS服務器有一個緩存功能, 能夠記住以前查詢過的域名。若是要查詢的域名和相關信息已經在緩存中,那麼就 能夠直接返回響應,接下來的查詢能夠從緩存的位置開始向下進行。相比每次都從 根域找起來講,緩存能夠減小查詢所需的時間。
而且,當要查詢的域名不存在時,「不存在」這一響應結果也會被緩存。這樣,當 下次查詢這個不存在的域名時,也能夠快速響應。
這個緩存機制中有一點須要注意,那就是信息被緩存後,本來的註冊信息可能會發 生改變,這時緩存中的信息就有多是不正確的。所以,DNS服務器中保存的信息都 設置有一個有效期,當緩存中的信息超過有效期後,數據就會從緩存中刪除。而 且,在對查詢進行響應時,DNS服務器也會告知客戶端這一響應的結果是來自緩存中 仍是來自負責管理該域名的DNS服務器。
知道了IP地址以後,就能夠委託操做系統內部的協議棧向這個目標IP地址發送消息。
向操做系統內部的協議棧發出委託時,須要按照指定的順序來調用Socket庫中的程 序組件。首先咱們解釋一下什麼是協議棧以及套接字。
操做系統中的網絡控制軟件稱之爲協議棧,表面上是看不出來的,比較抽象。
分爲4個部分,之間的上下關係是遵循必定規則。最上層是網絡應用層程序,其中包含瀏覽器、電子郵件客戶端、Web服務器等,接下來是Socket庫,其中包含DNS解析器
接下來就是操做系統內部TCP、UDP他們接受應用程序委託執行收發數據的操做。IP協議負責控制網絡包收發操做,將網絡包分割成一個一個網絡包,並進行傳輸。在IP協議中存在着ARP協議和ICMP協議,ARP協議用於根據IP地址查詢相應的以太網MAC地址
IP層下面就是網卡驅動程序,負責控制網卡硬件,最下面的網卡則負責實際的收發操做。
在協議棧內部,有一塊內存空間存放着控制信息的內存空間,這裏記錄了控制信息,一般包含通訊雙方的IP地址、端口號、通訊狀態等。協議棧須要經過這些控制信息判斷下一步的行動,這些控制信息一般稱之爲套接字。
瞭解協議棧和套接字以後,咱們來看一下調用Socket庫的具體過程。
經過調用socket函數,首先分配一個套接字所須要的內存空間,而後寫入初始化狀態。
初始化後,瀏覽器會調用connect函數,隨後的協議會將本地的套接字與服務器的套接字進行鏈接。
經過調用connect函數,經過TCP頭部中的發送方和接收方端口號能夠找到要鏈接的套接字,將頭部的控制位SYN比特設置爲1,表示能夠鏈接。同時設置適當的序號和窗口大小。
找到服務器的套接字後,套接字中會寫入相應的控制信息,將狀態更改成正在鏈接。
服務器開始返回響應,在TCP頭部中寫入對方的IP地址、端口號,以及SYN比特。同時將ACK控制位設置爲1.表示已經接收到相應的網絡包。(在網絡傳輸過程當中,常常會發生錯誤網絡包所以丟失。所以雙方在通訊時必須相互確認網絡包是否已經送達而設置ACK比特就是用來進行這一確認的)
網絡包返回到客戶端後,經過IP模塊到達TCP模塊,並經過TCP頭部的信息確認鏈接服務器的操做是否成功。當確認成功後,會向套接字中寫入服務器的IP地址、端口號信息,將狀態更改成鏈接完畢。同時響應服務器,將控制位的ACK比特設置爲1併發回服務器。
當服務器收到這個返回包後,鏈接操做完成,如今的套接字隨時能夠進入收發數據的狀態。
經過調用write函數,把要發送的數據交給協議棧。協議棧收到數據後並非立刻發送出去,而是將數據存放在內部的發送緩存區中,並等待應用程序的下一段數據。
這樣作的目的是:
優化網絡效率。若是收到數據就發送,就可能致使發送大量的小包數據。
關於累計多少數據才能發送跟下面幾個要素來進行判斷:
第一個要素是判斷每一個網絡包能容納的數據長度。經過MTU參數(網絡包中最大長度,一般是1500字節)減去頭部(TCP頭部 IP頭部)的長度,獲得網絡包中可以容納的最大數據長度,稱之爲MSS。當發送緩衝區的數據長度超過或接近MSS時再發送數據,這樣能夠避免發送大量小包數據問題。
複製代碼
第二個要素是時間。若是應用程序發送數據頻率不高,每次都會等到緩衝長度接近MSS時才發送數據,會致使發送延遲。爲此協議棧內部有一個計時器,當通過必定時間後,就會把網絡包發送。
複製代碼
若是僅靠協議棧來判斷髮送的時機可能會致使一些問題,所以協議棧給應用程序保留了控制發送時機的能力。例如:
瀏覽器這種會話型應用程序在向服務器發送數據時,一般是使用直接發送的選項。好比指定「不等待填滿緩衝區直接發送」。從提升瀏覽器的響應速度,下降延遲。
一般HTTP請求消息不會太長,一個網絡包就能裝下。但若是是要提交表單數據,長度可能會超過一個網絡包所可以容納的數據量。例如博客、論壇、評論等場景。
這種狀況下,發送緩衝區數據長度就會超過MSS,因此數據會以MSS爲單位進行拆分,將拆分出來的每塊數據放進單獨的網絡包中。
當要發送這些網絡包時,會在數據包前面打上TCP頭部,而且根據套接字中記錄的控制信息,標記IP地址和端口號後轉交給IP模塊進行發送操做。
由於TCP協議是提供可靠的字節流服務,因此具有確認對方是否接收到網絡包,以及當對方沒有收到時進行重發功能,所以在發送網絡包後,還須要進行確認操做。
TCP協議在進行拆分數據時,會計算好每一塊數據至關於從頭開始的第幾個字節,將計算好的字節數寫在TCP頭部中,這正是「序號」字段的做用。發送數據的長度是根據網絡包的長度減去頭部長度就能夠計算出來,因此不寫入TCP頭部中。
根據序號和數據長度就能夠準確知道數據是從第幾個字節開始,長度爲多少。而且接收方還能夠能確認收到的網絡包是否有遺漏。
若是沒有遺漏,接收方會計算如今一共收到多少字節,而後將這個數值寫入TCP頭部中的ACK號,回傳給發送方。返回的ACK號的操做稱爲確認響應。經過這樣的方式,發送方就可以確認對方到底收到了多少數據。
「序號」是經過隨機計算出一個初始值,避免數據被攻擊。所以在創建通訊的時候(三次握手時)須要將開始收發數據以前的隨機初始值通知通訊對象。在將SYN設置爲1時,還須要同時設置序號字段的隨機初始值。SYN(synchronize)的本質是經過告訴初始序號使得通訊雙發保持步調一致,以便完成後續的數據收發檢查。
TCP採用這種補救措施來確保對方是否接收到數據,在獲得對方確認之間,全部的數據將存放在發送緩衝區中,當對方沒有返回某個包對應的ACK號,就會從新發送這些包。
但若是發生網絡中斷,服務器宕機等問題,不管TCP怎樣重發數據確定是徒勞的。所以在TCP嘗試幾回無效重傳後會強制結束通訊,並嚮應用程序報錯。當網絡傳輸繁忙時就會發生擁塞,ACK號的返回會變慢。這時咱們就要將等待的時間設置的稍微長一點,避免發生重傳數據包以後前面的ACK號才姍姍來遲。
由於真實環境不可預測,因此將等待時間設置爲一個固定的值並非一件好辦法,所以TCP採用了動態調整等待時間的策略。簡單來講就是TCP會檢測ACK號的返回時間,當ACK號返回的變慢,則會延遲超時時間。當ACK返回變快時,相應的會縮短超時時間。
每發送一個包就等待一個ACK號的方式是最簡單最容易裏的方式。但等待ACK號這段時間,若是不作其餘事情,實在是太浪費效率了。所以TCP採用滑動窗口方式來管理數據發送和ACK號的操做。 簡單來講就是發送一個數據包後,不等待ACK號返回,而是直接發送下一個數據包,這樣就有效利用起來等待ACK號這段時間。
雖然這樣作可以減小等待ACK號所浪費的時間,可是若是不等待返回ACK號就連續發送包,會出現發送包頻率超過接收方處理能力的狀況。
爲了不接收緩衝區的數據溢出,能夠經過接收方告訴發送方我可以接受多少數據(TCP頭部中的窗口字段可以將本身可以接受的數據量告訴對方),而後發送方根據這個值對數據發送操做進行控制,這就是滑動窗口的基本思路。
要提升收發數據的效率,還須要考慮返回ACK號和更新窗口的時機。首先分別分析一下更新窗口和返回ACK號的時機。
當接收到的數據填入緩衝區時,不必向發送方更新窗口大小。由於發送方在每次發送數據時,減掉已經發送的數據長度就能夠自行計算出當前窗口的剩餘長度。所以更新窗口大小的時機是接收方從緩衝區取出數據傳遞給應用程序的時候,這個操做的時機是發送方沒法得知的。
所以當接收方將數據傳輸給應用程序時,致使緩衝區容量增長,就須要告知發送方。
當接收方收到數據時,若是確認沒有問題,就應該向發送方返回ACK號,所以咱們認爲應該收到數據以後就立刻進行這一操做
結合這兩個因素來分析,當發送方的數據到達後,馬上返回一個ACK號,當數據傳遞給應用程序後,更新窗口大小。若此以來,每收到一個包就須要分別發送ACK號和窗口更新的兩個單獨數據包,會致使網絡效率降低。
所以,接收方在發送ACK號和更新窗口時,並不會立刻把包發送出去,而是等待一段時間,將兩個通知合併成一個包進行回傳。
舉例來講:
當等待發送ACK號時,正好須要更新窗口,這時就能夠將數據合併成一個包,減小包的數量。
當須要連續發送多個ACK號時,也可減小包的數量。由於ACK號表示的是已經接受到的數據量,所以只發送最後一個ACK號就能夠,中間的能夠所有省略。
同理當須要發送多個窗口更新時也能夠減小包的數量,由於窗口大小表示緩衝區剩餘空間,所以只發送最後一個窗口大小,省略中間過程。
具體操做在發送消息的時候已經說明,在這裏簡單總結一下接受HTTP響應的過程。
瀏覽器委託協議棧發送請求消息以後,會調用read函數來獲取響應消息。控制流程會經過read函數轉移到協議棧,協議棧執行接下里的操做。
首先協議棧會檢查數據塊和TCP頭部信息,判斷數據是否有丟失,若是沒有問題返回ACK號。同時協議棧將數據暫存到接收緩衝區中,並將數據按順序鏈接起來還原出原始的數據,最後將數據交給應用程序。
收發數據結束的時間點應該是應用程序判斷全部數據已經發送完畢,這時候數據發送完畢的一放會發起斷開過程,但不一樣的應用程序也會選擇不一樣的斷開時機。
假設以服務器一方發起斷開過程
服務器會調用Socket庫中的close函數,生成包含斷開信息的TCP頭部,將控制位中的FIN比特設置爲1.同時套接中會記錄斷開操做的相關信息。
當收到服務器發來的FIN爲1的TCP頭部時,客戶端的協議棧也會將本身的套接字標記爲進入斷開操做狀態。爲了告知服務器已收到數據包,客戶端回傳一個ACK號。
只要接受服務器返回的全部數據,客戶端的操做也就隨之結束了。所以客戶端應用程序會調用close函數來結束收發操做。同服務器端同樣生成FIN比特爲1的TCP包委託IP模塊發送給服務器。
服務器收到後會返回一個ACK號,到如今,整個客戶端和服務器的通訊所有結束。
當瀏覽器拿到響應到的數據後,會... 瀏覽器是如何渲染出頁面的?
感謝各位大佬聽我叨叨完,文章是參考《網絡是怎樣鏈接》,固然各位大佬可能有些早已閱讀過,或者啃過經典大教材等等..快聖誕節了,也不知道送你們點什麼好..把我收藏的電子書送給你們吧(目前在看的)..還有各類學習資源。
雖然紙質書看起來舒服,可是電子書勝在便攜還有作筆記時候你懂的!
若是有須要的請私信我...記得點贊哈!資源就不截圖了,省得...侵權...
至此,從輸入url到瀏覽器的渲染就整理結束了,下一篇文仍是把學過的HTTP整理整理..
避免狗熊掰棒子。下回見,再見各位大佬!