整合營銷服務(wù)商

          電腦端+手機(jī)端+微信端=數(shù)據(jù)同步管理

          免費(fèi)咨詢熱線:

          在瀏覽器輸入 URL 回車之后發(fā)生了什么

          在瀏覽器輸入 URL 回車之后發(fā)生了什么

          這個問題已經(jīng)是老生常談了,更是經(jīng)常被作為面試的壓軸題出現(xiàn),網(wǎng)上也有很多文章,但最近閑的無聊,然后就自己做了一篇筆記,感覺比之前理解更透徹了。

          這篇筆記是我這兩天看了數(shù)十篇文章總結(jié)出來的,所以相對全面一點(diǎn),但由于我是做前端的,所以會比較重點(diǎn)分析瀏覽器渲染頁面那一部分,至于其他部分我會羅列出關(guān)鍵詞,感興趣的可以自行查閱.

          注意:本文的步驟是建立在,請求的是一個簡單的 HTTP 請求,沒有 HTTPS、HTTP2、最簡單的 DNS、沒有代理、并且服務(wù)器沒有任何問題的基礎(chǔ)上,盡管這是不切實際的。

          大致流程

          1. URL 解析
          2. DNS 查詢
          3. TCP 連接
          4. 處理請求
          5. 接受響應(yīng)
          6. 渲染頁面

          一、URL 解析

          地址解析:

          首先判斷你輸入的是一個合法的 URL 還是一個待搜索的關(guān)鍵詞,并且根據(jù)你輸入的內(nèi)容進(jìn)行自動完成、字符編碼等操作。

          HSTS

          由于安全隱患,會使用 HSTS 強(qiáng)制客戶端使用 HTTPS 訪問頁面。詳見:你所不知道的 HSTS[1]

          其他操作

          瀏覽器還會進(jìn)行一些額外的操作,比如安全檢查、訪問限制(之前國產(chǎn)瀏覽器限制 996.icu)。

          檢查緩存

          二、DNS 查詢

          基本步驟

          1. 瀏覽器緩存

          瀏覽器會先檢查是否在緩存中,沒有則調(diào)用系統(tǒng)庫函數(shù)進(jìn)行查詢。

          2. 操作系統(tǒng)緩存

          操作系統(tǒng)也有自己的 DNS緩存,但在這之前,會向檢查域名是否存在本地的 Hosts 文件里,沒有則向 DNS 服務(wù)器發(fā)送查詢請求。

          3. 路由器緩存

          路由器也有自己的緩存。

          4. ISP DNS 緩存

          ISP DNS 就是在客戶端電腦上設(shè)置的首選 DNS 服務(wù)器,它們在大多數(shù)情況下都會有緩存。

          根域名服務(wù)器查詢

          在前面所有步驟沒有緩存的情況下,本地 DNS 服務(wù)器會將請求轉(zhuǎn)發(fā)到互聯(lián)網(wǎng)上的根域,下面這個圖很好的詮釋了整個流程:

          根域名服務(wù)器(維基百科)

          需要注意的點(diǎn)

          1. 遞歸方式:一路查下去中間不返回,得到最終結(jié)果才返回信息(瀏覽器到本地DNS服務(wù)器的過程)
          2. 迭代方式,就是本地DNS服務(wù)器到根域名服務(wù)器查詢的方式。
          3. 什么是 DNS 劫持
          4. 前端 dns-prefetch 優(yōu)化

          三、TCP 連接

          TCP/IP 分為四層,在發(fā)送數(shù)據(jù)時,每層都要對數(shù)據(jù)進(jìn)行封裝:

          1. 應(yīng)用層:發(fā)送 HTTP 請求

          在前面的步驟我們已經(jīng)得到服務(wù)器的 IP 地址,瀏覽器會開始構(gòu)造一個 HTTP 報文,其中包括:

          • 請求報頭(Request Header):請求方法、目標(biāo)地址、遵循的協(xié)議等等
          • 請求主體(其他參數(shù))

          其中需要注意的點(diǎn):

          • 瀏覽器只能發(fā)送 GET、POST 方法,而打開網(wǎng)頁使用的是 GET 方法

          2. 傳輸層:TCP 傳輸報文

          傳輸層會發(fā)起一條到達(dá)服務(wù)器的 TCP 連接,為了方便傳輸,會對數(shù)據(jù)進(jìn)行分割(以報文段為單位),并標(biāo)記編號,方便服務(wù)器接受時能夠準(zhǔn)確地還原報文信息。

          在建立連接前,會先進(jìn)行 TCP 三次握手。

          關(guān)于 TCP/IP 三次握手,網(wǎng)上已經(jīng)有很多段子和圖片生動地描述了。相關(guān)知識點(diǎn):
          • SYN 泛洪攻擊

          3. 網(wǎng)絡(luò)層:IP協(xié)議查詢Mac地址

          將數(shù)據(jù)段打包,并加入源及目標(biāo)的IP地址,并且負(fù)責(zé)尋找傳輸路線。

          判斷目標(biāo)地址是否與當(dāng)前地址處于同一網(wǎng)絡(luò)中,是的話直接根據(jù) Mac 地址發(fā)送,否則使用路由表查找下一跳地址,以及使用 ARP 協(xié)議查詢它的 Mac 地址。

          注意:在 OSI 參考模型中 ARP 協(xié)議位于鏈路層,但在 TCP/IP 中,它位于網(wǎng)絡(luò)層。

          4. 鏈路層:以太網(wǎng)協(xié)議

          以太網(wǎng)協(xié)議

          根據(jù)以太網(wǎng)協(xié)議將數(shù)據(jù)分為以“幀”為單位的數(shù)據(jù)包,每一幀分為兩個部分:

          • 標(biāo)頭:數(shù)據(jù)包的發(fā)送者、接受者、數(shù)據(jù)類型
          • 數(shù)據(jù):數(shù)據(jù)包具體內(nèi)容

          Mac 地址

          以太網(wǎng)規(guī)定了連入網(wǎng)絡(luò)的所有設(shè)備都必須具備“網(wǎng)卡”接口,數(shù)據(jù)包都是從一塊網(wǎng)卡傳遞到另一塊網(wǎng)卡,網(wǎng)卡的地址就是 Mac 地址。每一個 Mac 地址都是獨(dú)一無二的,具備了一對一的能力。

          廣播

          發(fā)送數(shù)據(jù)的方法很原始,直接把數(shù)據(jù)通過 ARP 協(xié)議,向本網(wǎng)絡(luò)的所有機(jī)器發(fā)送,接收方根據(jù)標(biāo)頭信息與自身 Mac 地址比較,一致就接受,否則丟棄。

          注意:接收方回應(yīng)是單播。

          相關(guān)知識點(diǎn):
          • ARP 攻擊

          服務(wù)器接受請求

          接受過程就是把以上步驟逆轉(zhuǎn)過來,參見上圖。

          四、服務(wù)器處理請求

          大致流程

          HTTPD

          最常見的 HTTPD 有 Linux 上常用的 Apache 和 Nginx,以及 Windows 上的 IIS。

          它會監(jiān)聽得到的請求,然后開啟一個子進(jìn)程去處理這個請求。

          處理請求

          接受 TCP 報文后,會對連接進(jìn)行處理,對HTTP協(xié)議進(jìn)行解析(請求方法、域名、路徑等),并且進(jìn)行一些驗證:

          • 驗證是否配置虛擬主機(jī)
          • 驗證虛擬主機(jī)是否接受此方法
          • 驗證該用戶可以使用該方法(根據(jù) IP 地址、身份信息等)

          重定向

          假如服務(wù)器配置了 HTTP 重定向,就會返回一個 301永久重定向響應(yīng),瀏覽器就會根據(jù)響應(yīng),重新發(fā)送 HTTP 請求(重新執(zhí)行上面的過程)。

          關(guān)于更多:詳見這篇文章[2]

          URL 重寫

          然后會查看 URL 重寫規(guī)則,如果請求的文件是真實存在的,比如圖片、html、css、js文件等,則會直接把這個文件返回。

          否則服務(wù)器會按照規(guī)則把請求重寫到 一個 REST 風(fēng)格的 URL 上。

          然后根據(jù)動態(tài)語言的腳本,來決定調(diào)用什么類型的動態(tài)文件解釋器來處理這個請求。

          以 PHP 語言的 MVC 框架舉例,它首先會初始化一些環(huán)境的參數(shù),根據(jù) URL 由上到下地去匹配路由,然后讓路由所定義的方法去處理請求。

          五、瀏覽器接受響應(yīng)

          瀏覽器接收到來自服務(wù)器的響應(yīng)資源后,會對資源進(jìn)行分析。

          首先查看 Response header,根據(jù)不同狀態(tài)碼做不同的事(比如上面提到的重定向)。

          如果響應(yīng)資源進(jìn)行了壓縮(比如 gzip),還需要進(jìn)行解壓。

          然后,對響應(yīng)資源做緩存。

          接下來,根據(jù)響應(yīng)資源里的 MIME[3] 類型去解析響應(yīng)內(nèi)容(比如 HTML、Image各有不同的解析方式)。

          六、渲染頁面

          瀏覽器內(nèi)核

          不同的瀏覽器內(nèi)核,渲染過程也不完全相同,但大致流程都差不多。

          基本流程

          6.1. HTML 解析

          首先要知道瀏覽器解析是從上往下一行一行地解析的。

          解析的過程可以分為四個步驟:

          ① 解碼(encoding)

          傳輸回來的其實都是一些二進(jìn)制字節(jié)數(shù)據(jù),瀏覽器需要根據(jù)文件指定編碼(例如UTF-8)轉(zhuǎn)換成字符串,也就是HTML 代碼。

          ② 預(yù)解析(pre-parsing)

          預(yù)解析做的事情是提前加載資源,減少處理時間,它會識別一些會請求資源的屬性,比如img標(biāo)簽的src屬性,并將這個請求加到請求隊列中。

          ③ 符號化(Tokenization)

          符號化是詞法分析的過程,將輸入解析成符號,HTML 符號包括,開始標(biāo)簽、結(jié)束標(biāo)簽、屬性名和屬性值。

          它通過一個狀態(tài)機(jī)去識別符號的狀態(tài),比如遇到<,>狀態(tài)都會產(chǎn)生變化。

          ④ 構(gòu)建樹(tree construction)

          注意:符號化和構(gòu)建樹是并行操作的,也就是說只要解析到一個開始標(biāo)簽,就會創(chuàng)建一個 DOM 節(jié)點(diǎn)。

          在上一步符號化中,解析器獲得這些標(biāo)記,然后以合適的方法創(chuàng)建DOM對象并把這些符號插入到DOM對象中。


          <html><head> <title>Web page parsing</title></head><body> <div> <h1>Web page parsing</h1> <p>This is an example Web page.</p> </div></body></html>
          

          瀏覽器容錯進(jìn)制

          你從來沒有在瀏覽器看過類似”語法無效”的錯誤,這是因為瀏覽器去糾正錯誤的語法,然后繼續(xù)工作。

          事件

          當(dāng)整個解析的過程完成以后,瀏覽器會通過DOMContentLoaded事件來通知DOM解析完成。

          6.2. CSS 解析

          一旦瀏覽器下載了 CSS,CSS 解析器就會處理它遇到的任何 CSS,根據(jù)語法規(guī)范[4]解析出所有的 CSS 并進(jìn)行標(biāo)記化,然后我們得到一個規(guī)則表。

          CSS 匹配規(guī)則

          在匹配一個節(jié)點(diǎn)對應(yīng)的 CSS 規(guī)則時,是按照從右到左的順序的,例如:div p { font-size :14px }會先尋找所有的p標(biāo)簽然后判斷它的父元素是否為div。

          所以我們寫 CSS 時,盡量用 id 和 class,千萬不要過度層疊。

          6.3. 渲染樹

          其實這就是一個 DOM 樹和 CSS 規(guī)則樹合并的過程。

          注意:渲染樹會忽略那些不需要渲染的節(jié)點(diǎn),比如設(shè)置了display:none的節(jié)點(diǎn)。

          計算

          通過計算讓任何尺寸值都減少到三個可能之一:auto、百分比、px,比如把rem轉(zhuǎn)化為px。

          級聯(lián)

          瀏覽器需要一種方法來確定哪些樣式才真正需要應(yīng)用到對應(yīng)元素,所以它使用一個叫做specificity的公式,這個公式會通過:

          1. 標(biāo)簽名、class、id
          2. 是否內(nèi)聯(lián)樣式
          3. !important

          然后得出一個權(quán)重值,取最高的那個。

          渲染阻塞

          當(dāng)遇到一個script標(biāo)簽時,DOM 構(gòu)建會被暫停,直至腳本完成執(zhí)行,然后繼續(xù)構(gòu)建 DOM 樹。

          但如果 JS 依賴 CSS 樣式,而它還沒有被下載和構(gòu)建時,瀏覽器就會延遲腳本執(zhí)行,直至 CSS Rules 被構(gòu)建。

          所有我們知道:

          • CSS 會阻塞 JS 執(zhí)行
          • JS 會阻塞后面的 DOM 解析

          為了避免這種情況,應(yīng)該以下原則:

          • CSS 資源排在 JavaScript 資源前面
          • JS 放在 HTML 最底部,也就是 </body>前

          另外,如果要改變阻塞模式,可以使用 defer 與 async,詳見:這篇文章[5]

          6.4. 布局與繪制

          確定渲染樹種所有節(jié)點(diǎn)的幾何屬性,比如:位置、大小等等,最后輸入一個盒子模型,它能精準(zhǔn)地捕獲到每個元素在屏幕內(nèi)的準(zhǔn)確位置與大小。

          然后遍歷渲染樹,調(diào)用渲染器的 paint() 方法在屏幕上顯示其內(nèi)容。

          6.5. 合并渲染層

          把以上繪制的所有圖片合并,最終輸出一張圖片。

          6.6. 回流與重繪

          回流(reflow)

          當(dāng)瀏覽器發(fā)現(xiàn)某個部分發(fā)現(xiàn)變化影響了布局時,需要倒回去重新渲染,會從html標(biāo)簽開始遞歸往下,重新計算位置和大小。

          reflow基本是無法避免的,因為當(dāng)你滑動一下鼠標(biāo)、resize 窗口,頁面就會產(chǎn)生變化。

          重繪(repaint)

          改變了某個元素的背景色、文字顏色等等不會影響周圍元素的位置變化時,就會發(fā)生重繪。

          每次重繪后,瀏覽器還需要合并渲染層并輸出到屏幕上。

          回流的成本要比重繪高很多,所以我們應(yīng)該盡量避免產(chǎn)生回流。

          比如:

          • display:none 會觸發(fā)回流,而 visibility:hidden 只會觸發(fā)重繪。

          6.7. JavaScript 編譯執(zhí)行

          大致流程

          可以分為三個階段:

          1. 詞法分析

          JS 腳本加載完畢后,會首先進(jìn)入語法分析階段,它首先會分析代碼塊的語法是否正確,不正確則拋出“語法錯誤”,停止執(zhí)行。

          幾個步驟:

          • 分詞,例如將var a=2,,分成var、a、=、2這樣的詞法單元。
          • 解析,將詞法單元轉(zhuǎn)換成抽象語法樹(AST)。
          • 代碼生成,將抽象語法樹轉(zhuǎn)換成機(jī)器指令。

          2. 預(yù)編譯

          JS 有三種運(yùn)行環(huán)境:

          • 全局環(huán)境
          • 函數(shù)環(huán)境
          • eval

          每進(jìn)入一個不同的運(yùn)行環(huán)境都會創(chuàng)建一個對應(yīng)的執(zhí)行上下文,根據(jù)不同的上下文環(huán)境,形成一個函數(shù)調(diào)用棧,棧底永遠(yuǎn)是全局執(zhí)行上下文,棧頂則永遠(yuǎn)是當(dāng)前執(zhí)行上下文。

          創(chuàng)建執(zhí)行上下文

          創(chuàng)建執(zhí)行上下文的過程中,主要做了以下三件事:

          • 創(chuàng)建變量對象
          • 參數(shù)、函數(shù)、變量
          • 建立作用域鏈
          • 確認(rèn)當(dāng)前執(zhí)行環(huán)境是否能訪問變量
          • 確定 This 指向

          3. 執(zhí)行

          JS 線程

          雖然 JS 是單線程的,但實際上參與工作的線程一共有四個:

          其中三個只是協(xié)助,只有 JS 引擎線程是真正執(zhí)行的

          • JS 引擎線程:也叫 JS 內(nèi)核,負(fù)責(zé)解析執(zhí)行 JS 腳本程序的主線程,例如 V8 引擎
          • 事件觸發(fā)線程:屬于瀏覽器內(nèi)核線程,主要用于控制事件,例如鼠標(biāo)、鍵盤等,當(dāng)事件被觸發(fā)時,就會把事件的處理函數(shù)推進(jìn)事件隊列,等待 JS 引擎線程執(zhí)行
          • 定時器觸發(fā)線程:主要控制setInterval和setTimeout,用來計時,計時完畢后,則把定時器的處理函數(shù)推進(jìn)事件隊列中,等待 JS 引擎線程。
          • HTTP 異步請求線程:通過XMLHttpRequest連接后,通過瀏覽器新開的一個線程,監(jiān)控readyState狀態(tài)變更時,如果設(shè)置了該狀態(tài)的回調(diào)函數(shù),則將該狀態(tài)的處理函數(shù)推進(jìn)事件隊列中,等待JS引擎線程執(zhí)行。

          注:瀏覽器對同一域名的并發(fā)連接數(shù)是有限的,通常為 6 個。

          宏任務(wù)

          分為:

          • 同步任務(wù):按照順序執(zhí)行,只有前一個任務(wù)完成后,才能執(zhí)行后一個任務(wù)
          • 異步任務(wù):不直接執(zhí)行,只有滿足觸發(fā)條件時,相關(guān)的線程將該異步任務(wù)推進(jìn)任務(wù)隊列中,等待JS引擎主線程上的任務(wù)執(zhí)行完畢時才開始執(zhí)行,例如異步Ajax、DOM事件,setTimeout等。

          微任務(wù)

          微任務(wù)是ES6和Node環(huán)境下的,主要 API 有:Promise,process.nextTick。

          微任務(wù)的執(zhí)行在宏任務(wù)的同步任務(wù)之后,在異步任務(wù)之前。

          代碼例子


          console.log('1'); // 宏任務(wù) 同步
          setTimeout(function() { console.log('2'); // 宏任務(wù) 異步})
          new Promise(function(resolve) { console.log('3'); // 宏任務(wù) 同步 resolve();}).then(function() { console.log('4') // 微任務(wù)})
          console.log('5') // 宏任務(wù) 同步
          

          以上代碼輸出順序為:1,3,5,4,2

          來源:4ark.me/post/b6c7c0a2.html,侵刪

          者 | MageByte團(tuán)隊

          來源 | 碼哥字節(jié)(ID:MageByte)

          頭圖 | CSDN 下載自東方IC

          詳解輸入網(wǎng)址點(diǎn)擊回車,后臺到底發(fā)生了什么。透析 HTTP 協(xié)議與 TCP 連接之間的千絲萬縷的關(guān)系。掌握為何是三次握手四次揮手?time_wait 存在的意義是什么?全面圖解重點(diǎn)問題,再也不用擔(dān)心面試問這個問題。

          大致流程

          • URL 解析,解析 http 協(xié)議、端口、資源地址。

          • DNS 查詢:首先查詢本地 host,再訪問 DNS 服務(wù)器將 域名解析成 ip 地址。

          • 建立 TCP 連接。

          • 服務(wù)器收到請求后處理,并且構(gòu)造響應(yīng)返回給客戶端。

          • 客戶端接收 HTTP 報文響應(yīng)。

          • 渲染頁面,最后有可能會四次揮手?jǐn)嚅_連接,也可能不會而是復(fù)用連接。

          重點(diǎn)來了:

          • 如何理解 TCP 的三次握手與四次揮手?每次握手客戶端與服務(wù)端是怎樣的狀態(tài)?

          • 為何揮手會出現(xiàn) 2MSL,遇到大量 Socket 處在 TIME_WAIT 或者 CLOSE_WAIT 狀態(tài)是什么問題?

          • 三次握手與四次揮手的過程是怎樣的?

          • HTTP 的報文格式又是怎樣的?

          繼續(xù)閱讀本文,且聽碼哥字節(jié)答疑解惑,微信搜索 “碼哥字節(jié)”,關(guān)注公眾號更多硬核。

          URL 解析

          比如【碼哥字節(jié)】在思否發(fā)布的一篇文章的地址:https://segmentfault.com/a/1190000023475177。url 遵守的規(guī)則是這個樣子

          scheme://host.domain:port/path/filename

          每個名詞的含義如下解釋:

          • scheme 定義應(yīng)用層協(xié)議類型,比如 http、https、 ftp 等;

          • host 定義域主機(jī)(http 的默認(rèn)主機(jī)是 www);

          • domain 定義因特網(wǎng)域名,比如 segmentfault.com;

          • port 主機(jī)的端口,http 默認(rèn)是 80, https 默認(rèn)是 443;

          • path 服務(wù)器上的資源路徑;

          • filename - 定義文檔/資源的名稱;

          DNS 查詢

          瀏覽器不能直接通過域名找到服務(wù)器,只能通過 IP 地址。

          那瀏覽器是如何通過域名查詢到我們輸入的 url 對應(yīng)的 IP 呢?

          • 瀏覽器緩存:按照一定頻率緩存 DNS 數(shù)據(jù)。

          • 操作系統(tǒng)緩存:如果瀏覽器緩存好啊不到記錄則去操作系統(tǒng)中找。

          • 路由緩存:路由器 DNS 緩存。

          • ISP 的 DNS 服務(wù)器:ISP 是互聯(lián)網(wǎng)服務(wù)提供商(Internet Service Provider)的簡稱,ISP 有專門的 DNS 服務(wù)器應(yīng)對 DNS 查詢請求。

          • 根服務(wù)器:ISP 的 DNS 服務(wù)器還找不到的話,它就會向根服務(wù)器發(fā)出請求,進(jìn)行遞歸查詢(DNS 服務(wù)器先問根域名服務(wù)器.com 域名服務(wù)器的 IP 地址,然后再問 .baidu 域名服務(wù)器,依次類推)

          TCP 連接建立與斷開

          通過域名解析出 IP 地址以后就要建立 TCP/IP 連接了。

          TCP/IP 分為四層,每一層都會加上一個頭部再發(fā)送給下一層。到了接收方后,對應(yīng)的每一層則把對應(yīng)層的頭部解析拆除,丟上上一層,跟發(fā)送端的過程反過來。

          TCP/IP四層模型

          1、應(yīng)用層:發(fā)送 HTTP 請求

          瀏覽器從地址欄得到服務(wù)器 IP,接著構(gòu)造一個 HTTP 報文,其中包括:

          • 請求行包含請求方法、URL、協(xié)議版本

          • 請求報頭(Request Header):由 “關(guān)鍵字: 值”對組成,每行一對,關(guān)鍵字與值使用英文 “:” 分割

          • 請求體:請求參數(shù),并不是所有的請求有又請求參數(shù)。一般 get 參數(shù) 的格式 name=tom&password=1234&realName=tomson,也可以將參數(shù)放在 body 里面。

          2、傳輸層:TCP 傳輸報文

          在傳輸報文之前會先建立 TCP/IP 連接,也就是后面我們要說的三次握手。

          在這一層解決了數(shù)據(jù)可靠傳輸、及流量控制、擁塞控制。

          可靠傳輸

          對于發(fā)送方發(fā)送的數(shù)據(jù),接收方在接受到數(shù)據(jù)之后必須要給予確認(rèn),確認(rèn)它收到了數(shù)據(jù)。如果在規(guī)定時間內(nèi),沒有給予確認(rèn)則意味著接收方?jīng)]有接受到數(shù)據(jù),然后發(fā)送方對數(shù)據(jù)進(jìn)行重發(fā)。

          TCP的可靠傳輸是通過確認(rèn)和超時重傳的機(jī)制來實現(xiàn)的,而確認(rèn)和超時重傳的具體的實現(xiàn)是通過以字節(jié)為單位的滑動窗口機(jī)制來完成。

          TCP擁塞控制

          TCP協(xié)議通過慢啟動機(jī)制、擁塞避免機(jī)制、加速遞減機(jī)制、快重傳和快恢復(fù)機(jī)制來共同實現(xiàn)擁塞控制。

          流量控制

          采用通知窗口實現(xiàn)對發(fā)送端的流量控制,通知窗口大小的單位是字節(jié)。TCP通過在TCP數(shù)據(jù)段首部的窗口字段中填入當(dāng)前設(shè)定的接收窗口(即通知窗口)的大小,用來告知對方 '我方當(dāng)前的接收窗口大小',以實現(xiàn)流量控制。

          通信雙方的發(fā)送窗口大小由雙方在連接建立的時候商定,在通信過程,雙方可以動態(tài)地根據(jù)自己的情況調(diào)整對方的發(fā)送窗口大小。

          3、網(wǎng)絡(luò)層:IP 協(xié)議查詢 MAC 地址

          將數(shù)據(jù)段打包,并加入源及目標(biāo)的 IP 地址,并且負(fù)責(zé)尋找傳輸路線。判斷目標(biāo)地址是否與當(dāng)前地址處于同一網(wǎng)絡(luò)中,是的話直接根據(jù) Mac 地址發(fā)送,否則使用路由表查找下一跳地址,以及使用 ARP 協(xié)議查詢它的 Mac 地址。

          4、鏈路層:以太網(wǎng)協(xié)議

          根據(jù)以太網(wǎng)協(xié)議將數(shù)據(jù)分為以“幀”為單位的數(shù)據(jù)包,每一幀分為兩個部分:

          • 標(biāo)頭:數(shù)據(jù)包的發(fā)送者、接受者、數(shù)據(jù)類型

          • 數(shù)據(jù):數(shù)據(jù)包具體內(nèi)容

          5、Mac 地址

          以太網(wǎng)規(guī)定了連入網(wǎng)絡(luò)的所有設(shè)備都必須具備“網(wǎng)卡”接口,數(shù)據(jù)包都是從一塊網(wǎng)卡傳遞到另一塊網(wǎng)卡,網(wǎng)卡的地址就是 Mac 地址。每一個 Mac 地址都是獨(dú)一無二的,具備了一對一的能力。

          6、三次握手

          在傳輸層傳輸數(shù)據(jù)之前需要建立連接,也就是三次握手創(chuàng)建可靠連接。

          三次握手

          首先建立鏈接前需要 Server 端先監(jiān)聽端口,因此 Server 端建立鏈接前的初始狀態(tài)就是 LISTEN 狀態(tài),這時 Client 端準(zhǔn)備建立鏈接,先發(fā)送一個 SYN 同步包,發(fā)送完同步包后,Client 端的鏈接狀態(tài)變成了 SYN_SENT 狀態(tài)。Server 端收到 SYN 后,同意建立鏈接,會向 Client 端回復(fù)一個 ACK。

          由于 TCP 是雙工傳輸,Server 端也會同時向 Client 端發(fā)送一個 SYN,申請 Server 向 Client 方向建立鏈接。發(fā)送完 ACK 和 SYN 后,Server 端的鏈接狀態(tài)就變成了 SYN_RCVD。

          Client 收到 Server 的 ACK 后,Client 端的鏈接狀態(tài)就變成了 ESTABLISHED 狀態(tài),同時,Client 向 Server 端發(fā)送 ACK,回復(fù) Server 端的 SYN 請求。

          Server 端收到 Client 端的 ACK 后,Server 端的鏈接狀態(tài)也就變成了的 ESTABLISHED 狀態(tài),此時建連完成,雙方隨時可以進(jìn)行數(shù)據(jù)傳輸。

          在面試時需要明白三次握手是為了建立雙向的鏈接,需要記住 Client 端和 Server 端的鏈接狀態(tài)變化。另外回答建連的問題時,可以提到 SYN 洪水攻擊發(fā)生的原因,就是 Server 端收到 Client 端的 SYN 請求后,發(fā)送了 ACK 和 SYN,但是 Client 端不進(jìn)行回復(fù),導(dǎo)致 Server 端大量的鏈接處在 SYN_RCVD 狀態(tài),進(jìn)而影響其他正常請求的建連。可以設(shè)置 tcp_synack_retries=0 加快半鏈接的回收速度,或者調(diào)大 tcp_max_syn_backlog 來應(yīng)對少量的 SYN 洪水攻擊。

          7、四次揮手

          我們只要關(guān)注 80 端口與 13743 端口建立的連接斷開過程,瀏覽器通過 13747 端口發(fā)送 [FIN, ACK] 這里是不是跟很多網(wǎng)上看到的不一樣?

          1. 其實是客戶端在發(fā)送 [FIN] 報文的時候順帶發(fā)了一個 [ACK] 確認(rèn)上次傳輸確認(rèn)。

          2. 接著服務(wù)端通過 80 端口響應(yīng)了 [ACK] ,然后立馬響應(yīng) [FIN, ACK] 表示數(shù)據(jù)傳輸完了,可以關(guān)閉連接。

          3. 最后瀏覽器通過 13743 端口 發(fā)送 [ACK] 包給服務(wù)端,客服端與服務(wù)端連接就關(guān)閉了。

          具體流程如下圖抓包所示:

          四次揮手

          三次握手與四次揮手

          TCP 連接與斷開

          客戶端:

          • SYN_SENT - 客戶端發(fā)起第 1 次握手后,連接狀態(tài)為 SYN_SENT ,等待服務(wù)端內(nèi)核進(jìn)行應(yīng)答,如果服務(wù)端來不及處理(例如服務(wù)端的 backlog 隊列已滿)就可以看到這種狀態(tài)的連接。

          • ESTABLISHED - 表示連接處于正常狀態(tài),可以進(jìn)行數(shù)據(jù)傳送。客戶端收到服務(wù)器回復(fù)的 SYN+ACK 后,對服務(wù)端的 SYN 單獨(dú)回復(fù)(第 3 次握手),連接建立完成,進(jìn)入 ESTABLISHED 狀態(tài)。服務(wù)端程序收到第 3 次握手包后,也進(jìn)入 ESTABLISHED 狀態(tài)。

          • FIN_WAIT_1 - 客戶端發(fā)送了關(guān)閉連接的 FIN 報文后,等待服務(wù)端回復(fù) ACK 確認(rèn)。

          • FIN_WAIT_2 - 表示我方已關(guān)閉連接,正在等待服務(wù)端關(guān)閉。客戶端發(fā)了關(guān)閉連接的 FIN 報文后,服務(wù)器發(fā)回 ACK 應(yīng)答,但是沒進(jìn)行關(guān)閉,就會處于這種狀態(tài)。

          • TIME_WAIT - 雙方都正常關(guān)閉連接后,客戶端會維持 TIME_WAIT 一段時間,以確保最后一個 ACK 能成功發(fā)送到服務(wù)器端。停留時長為 2 倍的 MSL (報文最大生存時間),Linux 下大約是 60 秒。所以在一個頻繁建立短連接的服務(wù)器上通常可以看到成千上萬的 TIME_WAIT 連接。

          服務(wù)端:

          • LISTEN - 表示當(dāng)前程序正在監(jiān)聽某個端口時。

          • SYN_RCVD - 服務(wù)端收到第 1 次握手后,進(jìn)入 SYN_RCVD 狀態(tài),并回復(fù)一個 SYN+ACK(第 2 次握手),再等待對方確認(rèn)。

          • ESTABLISHED - 表示連接處于正常狀態(tài),可以進(jìn)行數(shù)據(jù)傳送。完成 TCP3 次握手后,連接建立完成,進(jìn)入 ESTABLISHED 狀態(tài)。

          • CLOSE_WAIT - 表示客戶端已經(jīng)關(guān)閉連接,但是本地還沒關(guān)閉,正在等待本地關(guān)閉。有時客戶端程序已經(jīng)退出了,但服務(wù)端程序由于異常或 BUG 沒有調(diào)用 close函數(shù)對連接進(jìn)行關(guān)閉,那在服務(wù)器這個連接就會一直處于 CLOSE_WAIT 狀態(tài),而在客戶機(jī)已經(jīng)不存在這個連接了。

          • LAST_ACK - 表示正在等待客戶端對服務(wù)端的關(guān)閉請求進(jìn)行最終確認(rèn)。

          TIME_WAIT 狀態(tài)存在的理由:

          劃重點(diǎn)了

          • 可靠地實現(xiàn) TCP 全雙工連接的終止 在進(jìn)行關(guān)閉連接四路握手協(xié)議時,最后的 ACK 是由主動關(guān)閉端發(fā)出的,如果這個最終的 ACK 丟失,服務(wù)器將重發(fā)最終的 FIN,因此客戶端必須維護(hù)狀態(tài)信息允 許它重發(fā)最終的 ACK。如 果不維持這個狀態(tài)信息,那么客戶端將響應(yīng) RST 分節(jié),服務(wù)器將此分節(jié)解釋成一個錯誤( 在 java 中會拋出 connection reset 的 SocketException)。因而,要實現(xiàn) TCP 全雙工連接的正常終 止,必須處理終止序列四個分節(jié)中任何一個分節(jié)的丟失情況,主動關(guān)閉 的客戶端必須維持狀 態(tài)信息進(jìn)入 TIME_WAIT 狀態(tài)。

          • 允許老的重復(fù)分節(jié)在網(wǎng)絡(luò)中消逝 TCP 分節(jié)可能由于路由器異常而“迷途”,在迷途期間,TCP 發(fā)送端可能因確認(rèn)超時而重發(fā)這個 分節(jié),迷途的分節(jié)在路由器修復(fù)后也會被送到最終目的地,這個 原來的迷途分節(jié)就稱為 lost duplicate。在關(guān)閉一個 TCP 連接后,馬上又重新建立起一個相同的 IP 地址和端口之間的 TCP 連接,后一個連接被稱為前一個連接的化身 ( incarnation),那么有可能出現(xiàn)這種情況,前一 個連接的迷途重復(fù)分組在前一個連接終止后出現(xiàn),從而被誤解成從屬于新的化身。為了避免 這個情 況,TCP 不允許處于 TIME_WAIT 狀態(tài)的連接啟動一個新的化身,因為 TIME_WAIT 狀 態(tài)持續(xù) 2MSL,就可以保證當(dāng)成功建立一個 TCP 連接的時 候,來自連接先前化身的重復(fù)分組已 經(jīng)在網(wǎng)絡(luò)中消逝。

          另外回答斷鏈的問題時,可以提到實際應(yīng)用中有可能遇到大量 Socket 處在 TIME_WAIT 或者 CLOSE_WAIT 狀態(tài)的問題。一般開啟 tcp_tw_reuse 和 tcp_tw_recycle 能夠加快 TIME-WAIT 的 Sockets 回收;而大量 CLOSE_WAIT 可能是被動關(guān)閉的一方存在代碼 bug,沒有正確關(guān)閉鏈接導(dǎo)致的。

          簡單地說就是

          1. 保證 TCP 協(xié)議的全雙工連接能夠可靠關(guān)閉;

          2. 保證這次連接的重復(fù)數(shù)據(jù)段從網(wǎng)絡(luò)中消失,防止端口被重用時可能產(chǎn)生數(shù)據(jù)混淆;

          服務(wù)器處理請求并響應(yīng) HTTP 報文

          深入分析下 HTTP 報文到底是什么玩意。數(shù)據(jù)傳輸都是通過 TCP/IP 協(xié)議負(fù)責(zé)底層的傳輸工作, HTTP 協(xié)議基本不用操心,所謂的 “超文本傳輸協(xié)議” 似乎不怎么例會 “傳輸” 這個事情,那 HTTP 的核心又是什么呢?

          比圖 TCP 報文,它在實際要傳輸?shù)臄?shù)據(jù)之前附加了一個 20 字節(jié)的頭部數(shù)據(jù),存儲 TCP 協(xié)議必須的額外信息,例如發(fā)送方的端口號、接收方的端口號、包序號、標(biāo)志位等等。

          有了這個附加的 TCP 頭,數(shù)據(jù)包才能夠正確傳輸,到了目的地后把頭部去掉,就可以拿到真正的數(shù)據(jù)。這個很容易理解,設(shè)置起點(diǎn)與終點(diǎn),不同協(xié)議貼上不同的頭部,到了對應(yīng)目的地就拆下這個頭部,提取真正的數(shù)據(jù)。

          HTTP報文

          與 TCP/UDP 類似需要在傳輸數(shù)據(jù)前設(shè)置一些請求頭,不同的是 HTTP 是一個 “純文本” 的協(xié)議,所有的頭都是 ASCII 碼的文本,很容易看出來是什么。

          再者就是他的請求報文與響應(yīng)報文的結(jié)構(gòu)基本一樣,主要三大部分組成:

          1. 起始行(Start Line):描述請求或者響應(yīng)的基本信息。

          2. Header:使用 key-value 的形式詳細(xì)說明報文信息。

          3. 空行。

          4. 消息正文(Entity):傳輸?shù)臄?shù)據(jù),圖片、視頻、文本等都可以。

          這其中前兩部分起始行和頭部字段經(jīng)常又合稱為“請求頭”或“響應(yīng)頭”,消息正文又稱為“實體”,但與“header”對應(yīng),很多時候就直接稱為“body”。

          敲黑板了

          HTTP 協(xié)議規(guī)定報文必須包含 Header,而且之后必須有一個 “空行”,也就是“CRLF”,十六進(jìn)制的“0D0A”,可以沒有 “body”。

          報文結(jié)構(gòu)如下圖所示:

          HTTP報文

          截取一段報文:

          透視HTTP協(xié)議

          請求頭-起始行

          請求行由請求方法字段、URL 字段和 HTTP 協(xié)議版本字段 3 個字段組成,它們用空格分隔。例如,GET / HTTP/1.1。

          HTTP 協(xié)議的請求方法有 GET、POST、HEAD、PUT、DELETE、OPTIONS、TRACE、CONNECT。

          GET 是請求方法, “/” 是請求的目標(biāo)資源,“HTTP/1.1” 請求協(xié)議版本號。

          GET / HTTP/1.1 翻譯成文字大概就是:“hello,服務(wù)器,我要請求根目錄下的默認(rèn)文件使用的是 HTTP 1.1 協(xié)議版本”。

          頭部 Header

          第二部分就是 Header,組成形式是 key:value,使用自定義頭需要注意事項:

          1. header 字段不區(qū)分大小寫,通常是首字母大寫;

          2. 字段名不允許有空格,可以使用 “-”,不能使用 “_”;

          3. 字段名必須緊接著 “:”,不能有空格,但是 “:” 后面可以有空格。

          4. 字段名順序沒有意義;

          瀏覽器接收響應(yīng)并渲染數(shù)據(jù)

          接收到響應(yīng)文本 HTML,則開始執(zhí)行瀏覽器渲染機(jī)制。

          不同的瀏覽器渲染可能有所差異,但是基本按照以下步驟執(zhí)行:

          1. 根據(jù) HTML 解析 DOM 樹;

          2. 根據(jù) CSS 解析出 CSS 規(guī)則樹;

          3. 結(jié)合 DOM 樹與 CSS 規(guī)則樹,生成渲染樹;

          4. 根據(jù)生成的渲染樹計算每個節(jié)點(diǎn)的信息;

          5. 根據(jù)節(jié)點(diǎn)信息繪制畫面展示給用戶。

          點(diǎn)分享

          1. 標(biāo)簽:又稱元素,是HTML的基本組成單位雙標(biāo)簽(絕大多數(shù)都是雙標(biāo)簽):<標(biāo)簽名>標(biāo)簽體</標(biāo)簽名>第一個標(biāo)簽叫起始標(biāo)簽,第二個標(biāo)簽叫結(jié)束標(biāo)簽例:<marquee>尚硅谷,讓天下沒有難學(xué)的技術(shù)!</marquee>單標(biāo)簽:<標(biāo)簽名/>/可以省略例:<input>
          2. 標(biāo)簽名不區(qū)分大小寫,但推薦小寫,因為小寫更規(guī)范
          3. 標(biāo)簽之間的關(guān)系:并列關(guān)系、嵌套關(guān)系,可以使用 tab 鍵進(jìn)行縮進(jìn)
          4. 1
            2
            3
            4
            5
            <marquee>
            尚硅谷,讓天下沒有難學(xué)的技術(shù)!
            <input>
            </marquee>
            <input>

          標(biāo)簽屬性

          1. 用于給標(biāo)簽提供附加信息
          2. 可以寫在起始標(biāo)簽或單標(biāo)簽中,形式如下:<標(biāo)簽名 屬性名="屬性值" 屬性名="屬性值">
          3. 1
            2
            <marquee loop="1" bgcolor="orange">尚硅谷,讓天下沒有難學(xué)的技術(shù)!</marquee>
            <input type="password">
          4. 有些特殊的屬性,沒有屬性名,只有屬性值,如:<input disabled>

          不同的標(biāo)簽,有不同的屬性;也有一些通用屬性(在任何標(biāo)簽內(nèi)都能寫)屬性名、屬性值不能亂寫,都是W3C規(guī)定好的屬性名、屬性值,都不區(qū)分大小寫,但推薦小寫雙引號,也可以寫成單引號,甚至不寫,但推薦寫雙引號標(biāo)簽中不要出現(xiàn)同名屬性,否則后寫的會失效,例如:<input type="text" type="password">

          基本結(jié)構(gòu)

          1. 想要呈現(xiàn)在網(wǎng)頁中的內(nèi)容寫在body標(biāo)簽中
          2. head標(biāo)簽中的內(nèi)容不會出現(xiàn)在網(wǎng)頁中
          3. head標(biāo)簽中的title標(biāo)簽可以指定網(wǎng)頁的標(biāo)題
          4. 1
            2
            3
            4
            5
            6
            7
            8
            <html>
            <head>
            <title>網(wǎng)頁標(biāo)題</title>
            </head>
            <body>
            ......
            </body>
            </html>

          注釋

          1. 特點(diǎn):注釋的內(nèi)容會被瀏覽器所忽略,不會呈現(xiàn)到頁面中,但源代碼中依然可見
          2. 作用:對代碼進(jìn)行解釋和說明
          3. 寫法
          4. 1
            2
            3
            4
            <!-- 下面的文字只能滾動一次 -->
            <marquee loop="1">尚硅谷</marquee>
            <!-- 下面的文字可以無限滾動 -->
            <marquee>尚硅谷123</marquee>
          5. 注釋不可以嵌套

          文檔聲明

          1. 作用:告訴瀏覽器當(dāng)前網(wǎng)頁的版本
          2. 寫法
            1. 舊寫法:要依網(wǎng)頁所用的HTML版本而定,寫法有很多參考:W3C QA - 可在 Web 文檔中使用的 Doctype 聲明的推薦列表
            2. 新寫法:W3C 推薦使用 HTML 5 的寫法
            3. 1
              2
              3
              4
              5
              <!DOCTYPE html>

              <!DOCTYPE HTML>

              <!doctype html>
          3. 文檔聲明必須在網(wǎng)頁的第一行,且在html標(biāo)簽的外側(cè)

          字符編碼

          1. 計算機(jī)對數(shù)據(jù)的操作存儲時,對數(shù)據(jù)進(jìn)行:編碼讀取時,對數(shù)據(jù)進(jìn)行:解碼
          2. 編碼、解碼,會遵循一定的規(guī)范 —— 字符集
          3. 常見的字符集ASCII:大寫字母、小寫字母、數(shù)字、一些符號,共計128個ISO 8859-1:在 ASCII 基礎(chǔ)上,擴(kuò)充了一些希臘字符等,共計是256個GB2312:繼續(xù)擴(kuò)充,收錄了 6763 個常用漢字、682個字符GBK:收錄了的漢字和符號達(dá)到 20000+ ,支持繁體中文UTF-8 :包含世界上所有文字與符號
          4. 為了讓瀏覽器在渲染html文件時,不犯錯誤,可以通過meta標(biāo)簽配合charset屬性指定字符編碼
          5. 1
            2
            3
            <head>
            <meta charset="UTF-8"/>
            </head>

          設(shè)置語言

          1. 主要作用讓瀏覽器顯示對應(yīng)的翻譯提示有利于搜索引擎優(yōu)化
          2. 具體寫法:<html lang="zh-CN">
          3. lang屬性的編寫規(guī)則語言-國家/地區(qū)zh-CN :中文-中國大陸(簡體中文)zh-TW :中文-中國臺灣(繁體中文)zh :中文en-US :英語-美國en-GB :英語-英國語言—具體種類(已不推薦使用)zh-Hans :中文—簡體zh-Hant :中文—繁體W3School 上的說明:《語言代碼參考手冊》 、《國家/地區(qū)代碼參考手冊》 W3C官網(wǎng)上的說明:《Language tags in HTML》

          標(biāo)準(zhǔn)結(jié)構(gòu)

          1. HTML標(biāo)準(zhǔn)結(jié)構(gòu)如下
          2. 1
            2
            3
            4
            5
            6
            7
            8
            9
            10
            11
            12
            13
            <!DOCTYPE html>
            <html lang="zh-CN">

            <head>
            <meta charset="UTF-8">
            <title>Document</title>
            </head>

            <body>

            </body>

            </html>

          VSCode 刪除行快捷鍵:Ctrl+Shift+K

          1. 輸入!,隨后回車即可快速生成標(biāo)準(zhǔn)結(jié)構(gòu)
          2. 配置VScode 的內(nèi)置插件 emmet ,可以對生成結(jié)構(gòu)的屬性進(jìn)行定制
          3. 在存放代碼的文件夾中,存放一個 favicon.ico 圖片,可配置網(wǎng)站圖標(biāo)

          主站蜘蛛池模板: 国产精品无码一区二区在线观| 欧美日韩国产免费一区二区三区 | 合区精品久久久中文字幕一区| 日韩精品无码视频一区二区蜜桃| 亚洲av日韩综合一区久热| 在线精品亚洲一区二区小说| 视频一区在线播放| 精品一区二区ww| 亚洲熟女综合色一区二区三区 | 国产精品av一区二区三区不卡蜜| 国产波霸爆乳一区二区| 精品日韩在线视频一区二区三区| 国产乱码精品一区二区三区四川| 免费无码一区二区三区蜜桃大| 97se色综合一区二区二区| 国产福利一区二区三区| 91在线一区二区| 亚洲国产福利精品一区二区| 日韩精品无码一区二区三区免费| 亚洲AV无码一区东京热久久| 亚洲一区二区三区香蕉| 久久一区二区三区免费播放| 久久久久久人妻一区精品| 无码av免费一区二区三区| 久久久久人妻精品一区| 亚洲国产精品综合一区在线 | 日本免费精品一区二区三区| 成人精品一区二区不卡视频| 国产精品无码一区二区三区在| 日本人的色道www免费一区| 立川理惠在线播放一区| 久久精品无码一区二区三区日韩| 中文字幕一区二区在线播放| 久久精品无码一区二区三区| 国产AV午夜精品一区二区入口 | 无码人妻一区二区三区av| 国产传媒一区二区三区呀| 好爽毛片一区二区三区四| 国产成人精品视频一区二区不卡 | 福利一区国产原创多挂探花| 红杏亚洲影院一区二区三区|