從輸入U(xiǎn)RL到頁面加載的過程
- 瀏覽器接收URL開啟網(wǎng)絡(luò)請求線程
- DNS查詢
- TCP/IP請求
- 服務(wù)器接收到請求、對應(yīng)后臺處理請求
- 后臺和前臺的HTTP交互
- 瀏覽器接收到HTTP數(shù)據(jù)包并解析
- 頁面渲染
- JS引擎解析
進(jìn)程和線程
進(jìn)程是CPU資源分配的最小單位,線程是CPU調(diào)度的最小單位
瀏覽器的進(jìn)程
- Browser進(jìn)程:瀏覽器的主進(jìn)程,負(fù)責(zé)協(xié)調(diào)、主控,只有一個(gè)。負(fù)責(zé)界面顯示、用戶交互、頁面管理、繪制、下載等
- 第三方插件進(jìn)程:每個(gè)插件對應(yīng)一個(gè)線程,使用時(shí)創(chuàng)建
- GPU線程,用于3D繪制
- 瀏覽器渲染進(jìn)程:默認(rèn)每個(gè)Tab頁一個(gè)進(jìn)程
瀏覽器多進(jìn)程的優(yōu)勢
- 避免單個(gè)page crash影響整個(gè)瀏覽器
- 避免第三方插件crash影響整個(gè)瀏覽器
- 多進(jìn)程充分利用多核優(yōu)勢
瀏覽器內(nèi)核進(jìn)程(tab頁面)的線程
- GUI線程(渲染界面)
- JS引擎線程
- 事件觸發(fā)線程(事件循環(huán))
- 定時(shí)器線程
- 網(wǎng)絡(luò)請求線程
其中GUI渲染線程和JS引擎是無法同時(shí)工作的
DNS查詢
- 瀏覽器緩存
- hosts
- 路由器緩存
- ISP(網(wǎng)絡(luò)服務(wù)提供商)
- 遞歸查詢
五層因特網(wǎng)協(xié)議棧
- 應(yīng)用層(HTTP)
- 傳輸層(TCP、UDP)
- 網(wǎng)絡(luò)層(IP)
- 數(shù)據(jù)鏈路層
- 物理層
TCP的三次握手
- 第一次握手(SYN=1, seq=x):
客戶端發(fā)送一個(gè) TCP 的 SYN 標(biāo)志位置1的包,指明客戶端打算連接的服務(wù)器的端口,以及初始序號 X,保存在包頭的序列號(Sequence Number)字段里。
發(fā)送完畢后,客戶端進(jìn)入 SYN_SEND 狀態(tài)。 - 第二次握手(SYN=1, ACK=1, seq=y, ACKnum=x+1):
服務(wù)器發(fā)回確認(rèn)包(ACK)應(yīng)答。即 SYN 標(biāo)志位和 ACK 標(biāo)志位均為1。服務(wù)器端選擇自己 ISN 序列號,放到 Seq 域里,同時(shí)將確認(rèn)序號(Acknowledgement Number)設(shè)置為客戶的 ISN 加1,即X+1。 發(fā)送完畢后,服務(wù)器端進(jìn)入 SYN_RCVD 狀態(tài)。 - 第三次握手(ACK=1,ACKnum=y+1)
客戶端再次發(fā)送確認(rèn)包(ACK),SYN 標(biāo)志位為0,ACK 標(biāo)志位為1,并且把服務(wù)器發(fā)來 ACK 的序號字段+1,放在確定字段中發(fā)送給對方,并且在數(shù)據(jù)段放寫ISN的+1
發(fā)送完畢后,客戶端進(jìn)入 ESTABLISHED 狀態(tài),當(dāng)服務(wù)器端接收到這個(gè)包時(shí),也進(jìn)入 ESTABLISHED 狀態(tài),TCP 握手結(jié)束。
TCP的四次揮手
- 第一次揮手(FIN=1,seq=x)
假設(shè)客戶端想要關(guān)閉連接,客戶端發(fā)送一個(gè) FIN 標(biāo)志位置為1的包,表示自己已經(jīng)沒有數(shù)據(jù)可以發(fā)送了,但是仍然可以接受數(shù)據(jù)。
發(fā)送完畢后,客戶端進(jìn)入 FIN_WAIT_1 狀態(tài)。 - 第二次揮手(ACK=1,ACKnum=x+1)
服務(wù)器端確認(rèn)客戶端的 FIN 包,發(fā)送一個(gè)確認(rèn)包,表明自己接受到了客戶端關(guān)閉連接的請求,但還沒有準(zhǔn)備好關(guān)閉連接。
發(fā)送完畢后,服務(wù)器端進(jìn)入 CLOSE_WAIT 狀態(tài),客戶端接收到這個(gè)確認(rèn)包之后,進(jìn)入 FIN_WAIT_2 狀態(tài),等待服務(wù)器端關(guān)閉連接。 - 第三次揮手(FIN=1,seq=y)
服務(wù)器端準(zhǔn)備好關(guān)閉連接時(shí),向客戶端發(fā)送結(jié)束連接請求,F(xiàn)IN 置為1。
發(fā)送完畢后,服務(wù)器端進(jìn)入 LAST_ACK 狀態(tài),等待來自客戶端的最后一個(gè)ACK。 - 第四次揮手(ACK=1,ACKnum=y+1)
客戶端接收到來自服務(wù)器端的關(guān)閉請求,發(fā)送一個(gè)確認(rèn)包,并進(jìn)入 TIME_WAIT狀態(tài),等待可能出現(xiàn)的要求重傳的 ACK 包。
服務(wù)器端接收到這個(gè)確認(rèn)包之后,關(guān)閉連接,進(jìn)入 CLOSED 狀態(tài)。
客戶端等待了某個(gè)固定時(shí)間(兩個(gè)最大段生命周期,2MSL,2 Maximum Segment Lifetime)之后,沒有收到服務(wù)器端的 ACK ,認(rèn)為服務(wù)器端已經(jīng)正常關(guān)閉連接,于是自己也關(guān)閉連接,進(jìn)入 CLOSED 狀態(tài)。
TCP和UDP的區(qū)別

粘包
默認(rèn)情況下, TCP 連接會啟用延遲傳送算法 (Nagle 算法), 在數(shù)據(jù)發(fā)送之前緩存他們. 如果短時(shí)間有多個(gè)數(shù)據(jù)發(fā)送, 會緩沖到一起作一次發(fā)送 (緩沖大小見 socket.bufferSize), 這樣可以減少 IO 消耗提高性能.
如果是傳輸文件的話, 那么根本不用處理粘包的問題, 來一個(gè)包拼一個(gè)包就好了. 但是如果是多條消息, 或者是別的用途的數(shù)據(jù)那么就需要處理粘包.
可以參見網(wǎng)上流傳比較廣的一個(gè)例子, 連續(xù)調(diào)用兩次 send 分別發(fā)送兩段數(shù)據(jù) data1 和 data2, 在接收端有以下幾種常見的情況:
A. 先接收到 data1, 然后接收到 data2 .
B. 先接收到 data1 的部分?jǐn)?shù)據(jù), 然后接收到 data1 余下的部分以及 data2 的全部.
C. 先接收到了 data1 的全部數(shù)據(jù)和 data2 的部分?jǐn)?shù)據(jù), 然后接收到了 data2 的余下的數(shù)據(jù).
D. 一次性接收到了 data1 和 data2 的全部數(shù)據(jù).
其中的 BCD 就是我們常見的粘包的情況. 而對于處理粘包的問題, 常見的解決方案有:
多次發(fā)送之前間隔一個(gè)等待時(shí)間
關(guān)閉 Nagle 算法
進(jìn)行封包/拆包
TCP流量控制
通過滑動窗口協(xié)議(連續(xù)ARQ協(xié)議)實(shí)現(xiàn),保證了分組無差錯(cuò)、有序接收、流量控制。接收方返回的ACK中會包含自己的接收窗口的大小,并且利用大小來控制發(fā)送方的數(shù)據(jù)發(fā)送。
TCP流量控制中的死鎖
當(dāng)發(fā)送者收到了一個(gè)窗口為0的應(yīng)答,發(fā)送者便停止發(fā)送,等待接收者的下一個(gè)應(yīng)答。如果這個(gè)窗口不為0的應(yīng)答在傳輸過程中丟失,發(fā)送者一直等待,接收者以為發(fā)送者收到該應(yīng)答,等待接收新數(shù)據(jù),這樣雙方就相互等待,從而產(chǎn)生死鎖
TCP流量控制中的死鎖的解決
TCP使用了持續(xù)計(jì)時(shí)器。每當(dāng)發(fā)送者收到一個(gè)0窗口的應(yīng)答后就啟動該計(jì)時(shí)器。計(jì)時(shí)器到時(shí)便主動發(fā)送報(bào)文詢問接收者的窗口大小。若接收者仍然返回0窗口,則重置該計(jì)時(shí)器繼續(xù)等待;若窗口不為0,則標(biāo)識應(yīng)答報(bào)文丟失了,此時(shí)重置發(fā)送窗口開始發(fā)送,這樣就避免了死鎖的產(chǎn)生
擁塞控制和流量控制的區(qū)別
擁塞控制是作用于網(wǎng)絡(luò)的,防止網(wǎng)絡(luò)負(fù)載過大,常用的方法:1.慢啟動、擁塞避免 2.快重傳、快恢復(fù)。流量控制是作用于接收者的,控制發(fā)送者的發(fā)送速度使接收者來得及接收,防止分組丟失
慢啟動算法
發(fā)送方維持一個(gè)叫做擁塞窗口CWnd的狀態(tài)變量,控制著傳輸速度,TCP開始發(fā)送報(bào)文時(shí)CWnd=1。一個(gè)傳輸輪次所經(jīng)歷的時(shí)間就是往返時(shí)間RTT,每經(jīng)過一個(gè)RTT并且按時(shí)收到確認(rèn),就將擁塞窗口CWnd加倍。還有一個(gè)叫慢啟動門限ssthresh的狀態(tài)變量,當(dāng)CWnd<ssthresh時(shí),使用慢啟動,當(dāng)CWnd>=ssthresh改用擁塞避免算法
擁塞避免算法
每經(jīng)過一個(gè)往返時(shí)間RTT就把發(fā)送方的擁塞窗口cwnd加1而不是加倍。無論在慢啟動階段還是擁塞避免階段,只要發(fā)送方?jīng)]有按時(shí)收到確認(rèn),就把慢啟動門限設(shè)置為出現(xiàn)擁塞時(shí)的擁塞窗口cwnd的一半(但不小于2)。然后把擁塞窗口cwnd重置為1,執(zhí)行慢啟動算法
快重傳算法
接收方收到一個(gè)失序的報(bào)文段后就立刻發(fā)出重復(fù)確認(rèn)而不是等到自己發(fā)送數(shù)據(jù)時(shí)捎帶確認(rèn)。只要發(fā)送方一連收到三個(gè)重復(fù)確認(rèn)就立即重傳對方尚未收到的報(bào)文段,而不是等待重傳計(jì)時(shí)器到期
快恢復(fù)算法
當(dāng)發(fā)送方連續(xù)收到三個(gè)重復(fù)確認(rèn)時(shí),把慢啟動門限ssthresh減半,但是并不執(zhí)行慢開始算法,而是將擁塞窗口cwnd設(shè)置為ssthresh減半后的值,直接執(zhí)行擁塞避免算法??熘貍髋浜峡旎謴?fù)的TCP Reno版本是目前使用最廣的版本。
HTTP報(bào)文結(jié)構(gòu)
- 通用頭部
- 請求/響應(yīng)頭部
- 請求/響應(yīng)體
常見請求頭部
Accept: 接收類型,表示瀏覽器支持的MIME類型(對標(biāo)服務(wù)端返回的Content-Type)
Accept-Encoding:瀏覽器支持的壓縮類型,如gzip等,超出類型不能接收
Content-Type:客戶端發(fā)送出去實(shí)體內(nèi)容的類型
Cache-Control: 指定請求和響應(yīng)遵循的緩存機(jī)制,如no-cache
If-Modified-Since:對應(yīng)服務(wù)端的Last-Modified,用來匹配看文件是否變動,只能精確到1s之內(nèi),http1.0中
Expires:緩存控制,在這個(gè)時(shí)間內(nèi)不會請求,直接使用緩存,http1.0,而且是服務(wù)端時(shí)間
Max-age:代表資源在本地緩存多少秒,有效時(shí)間內(nèi)不會請求,而是使用緩存,http1.1中
If-None-Match:對應(yīng)服務(wù)端的ETag,用來匹配文件內(nèi)容是否改變(非常精確),http1.1中
Cookie: 有cookie并且同域訪問時(shí)會自動帶上
Connection: 當(dāng)瀏覽器與服務(wù)器通信時(shí)對于長連接如何進(jìn)行處理,如keep-alive
Host:請求的服務(wù)器URL
Origin:最初的請求是從哪里發(fā)起的(只會精確到端口),Origin比Referer更尊重隱私
Referer:該頁面的來源URL(適用于所有類型的請求,會精確到詳細(xì)頁面地址,csrf攔截常用到這個(gè)字段)
User-Agent:用戶客戶端的一些必要信息,如UA頭部等
常見響應(yīng)頭部
Access-Control-Allow-Headers: 服務(wù)器端允許的請求Headers
Access-Control-Allow-Methods: 服務(wù)器端允許的請求方法
Access-Control-Allow-Origin: 服務(wù)器端允許的請求Origin頭部(譬如為*)
Content-Type:服務(wù)端返回的實(shí)體內(nèi)容的類型
Date:數(shù)據(jù)從服務(wù)器發(fā)送的時(shí)間
Cache-Control:告訴瀏覽器或其他客戶,什么環(huán)境可以安全的緩存文檔
Last-Modified:請求資源的最后修改時(shí)間
Expires:應(yīng)該在什么時(shí)候認(rèn)為文檔已經(jīng)過期,從而不再緩存它
Max-age:客戶端的本地資源應(yīng)該緩存多少秒,開啟了Cache-Control后有效
ETag:請求變量的實(shí)體標(biāo)簽的當(dāng)前值
Set-Cookie:設(shè)置和頁面關(guān)聯(lián)的cookie,服務(wù)器通過這個(gè)頭部把cookie傳給客戶端
Keep-Alive:如果客戶端有keep-alive,服務(wù)端也會有響應(yīng)(如timeout=38)
Server:服務(wù)器的一些相關(guān)信息
HTTP2.0相對于HTTP1.x有什么優(yōu)勢和特點(diǎn)
二進(jìn)制分幀
幀:HTTP/2 數(shù)據(jù)通信的最小單位消息:指 HTTP/2 中邏輯上的 HTTP 消息。例如請求和響應(yīng)等,消息由一個(gè)或多個(gè)幀組成。
流:存在于連接中的一個(gè)虛擬通道。流可以承載雙向消息,每個(gè)流都有一個(gè)唯一的整數(shù)ID
頭部壓縮
HTTP/1.x會在請求和響應(yīng)中中重復(fù)地?cái)y帶不常改變的、冗長的頭部數(shù)據(jù),給網(wǎng)絡(luò)帶來額外的負(fù)擔(dān)。
- HTTP/2在客戶端和服務(wù)器端使用“首部表”來跟蹤和存儲之前發(fā)送的鍵-值對,對于相同的數(shù)據(jù),不再通過每次請求和響應(yīng)發(fā)送
- 首部表在HTTP/2的連接存續(xù)期內(nèi)始終存在,由客戶端和服務(wù)器共同漸進(jìn)地更新
- 每個(gè)新的首部鍵-值對要么被追加到當(dāng)前表的末尾,要么替換表中之前的值
服務(wù)器推送
服務(wù)端可以在發(fā)送頁面HTML時(shí)主動推送其它資源,而不用等到瀏覽器解析到相應(yīng)位置,發(fā)起請求再響應(yīng)。例如服務(wù)端可以主動把JS和CSS文件推送給客戶端,而不需要客戶端解析HTML時(shí)再發(fā)送這些請求。
服務(wù)端可以主動推送,客戶端也有權(quán)利選擇是否接收。如果服務(wù)端推送的資源已經(jīng)被瀏覽器緩存過,瀏覽器可以通過發(fā)送RST_STREAM幀來拒收。主動推送也遵守同源策略,服務(wù)器不會隨便推送第三方資源給客戶端。
多路復(fù)用
HTTP 1.x 中,如果想并發(fā)多個(gè)請求,必須使用多個(gè) TCP 鏈接,且瀏覽器為了控制資源,還會對單個(gè)域名有 6-8個(gè)的TCP鏈接請求限制。
HTTP2中:
同域名下所有通信都在單個(gè)連接上完成。
單個(gè)連接可以承載任意數(shù)量的雙向數(shù)據(jù)流。
數(shù)據(jù)流以消息的形式發(fā)送,而消息又由一個(gè)或多個(gè)幀組成,多個(gè)幀之間可以亂序發(fā)送,因?yàn)楦鶕?jù)幀首部的流標(biāo)識可以重新組裝
HTTP的緩存過程
- 客戶端向服務(wù)器發(fā)出請求,請求資源
- 服務(wù)器返回資源,并通過響應(yīng)頭決定緩存策略
- 客戶端根據(jù)響應(yīng)頭的策略決定是否緩存資源(這里假設(shè)是),并將響應(yīng)頭與資源緩存下來
- 在客戶端再次請求且命中資源的時(shí)候,此時(shí)客戶端去檢查上次緩存的緩存策略,根據(jù)策略的不同、是否過期等判斷是直接讀取本地緩存還是與服務(wù)器協(xié)商緩存