終極解密輸入網(wǎng)址按回車到底發(fā)生了什么
詳解輸入網(wǎng)址點(diǎn)擊回車,后臺(tái)到底發(fā)生了什么。透析 HTTP 協(xié)議與 TCP 連接之間的千絲萬(wàn)縷的關(guān)系。掌握為何是三次握手四次揮手?time_wait 存在的意義是什么?全面圖解重點(diǎn)問(wèn)題,再也不用擔(dān)心面試問(wèn)這個(gè)問(wèn)題。
大致流程
URL 解析,解析 http 協(xié)議、端口、資源地址。
DNS 查詢:首先查詢本地 host,再訪問(wèn) DNS 服務(wù)器將 域名解析成 ip 地址。
建立 TCP 連接。
服務(wù)器收到請(qǐng)求后處理,并且構(gòu)造響應(yīng)返回給客戶端。
客戶端接收 HTTP 報(bào)文響應(yīng)。
渲染頁(yè)面,最后有可能會(huì)四次揮手?jǐn)嚅_(kāi)連接,也可能不會(huì)而是復(fù)用連接。
重點(diǎn)來(lái)了:
如何理解 TCP 的三次握手與四次揮手?每次握手客戶端與服務(wù)端是怎樣的狀態(tài)?
為何揮手會(huì)出現(xiàn) 2MSL,遇到大量 Socket 處在 TIME_WAIT 或者 CLOSE_WAIT 狀態(tài)是什么問(wèn)題?
三次握手與四次揮手的過(guò)程是怎樣的?
HTTP 的報(bào)文格式又是怎樣的?
?
URL 解析
url 遵守的規(guī)則是這個(gè)樣子
scheme://host.domain:port/path/filename
每個(gè)名詞的含義如下解釋:
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 查詢
瀏覽器不能直接通過(guò)域名找到服務(wù)器,只能通過(guò) IP 地址。
那瀏覽器是如何通過(guò)域名查詢到我們輸入的 url 對(duì)應(yīng)的 IP 呢?
瀏覽器緩存:按照一定頻率緩存 DNS 數(shù)據(jù)。
操作系統(tǒng)緩存:如果瀏覽器緩存好啊不到記錄則去操作系統(tǒng)中找。
路由緩存:路由器 DNS 緩存。
ISP 的 DNS 服務(wù)器:ISP 是互聯(lián)網(wǎng)服務(wù)提供商(Internet Service Provider)的簡(jiǎn)稱,ISP 有專門的 DNS 服務(wù)器應(yīng)對(duì) DNS 查詢請(qǐng)求。
根服務(wù)器:ISP 的 DNS 服務(wù)器還找不到的話,它就會(huì)向根服務(wù)器發(fā)出請(qǐng)求,進(jìn)行遞歸查詢(DNS 服務(wù)器先問(wèn)根域名服務(wù)器.com 域名服務(wù)器的 IP 地址,然后再問(wèn) .baidu 域名服務(wù)器,依次類推)
?
TCP 連接建立與斷開(kāi)
通過(guò)域名解析出 IP 地址以后就要建立 TCP/IP 連接了。
TCP/IP 分為四層,每一層都會(huì)加上一個(gè)頭部再發(fā)送給下一層。到了接收方后,對(duì)應(yīng)的每一層則把對(duì)應(yīng)層的頭部解析拆除,丟上上一層,跟發(fā)送端的過(guò)程反過(guò)來(lái)。

應(yīng)用層:發(fā)送 HTTP 請(qǐng)求
瀏覽器從地址欄得到服務(wù)器 IP,接著構(gòu)造一個(gè) HTTP 報(bào)文,其中包括:
請(qǐng)求行包含請(qǐng)求方法、URL、協(xié)議版本 請(qǐng)求報(bào)頭(Request Header):由 “關(guān)鍵字: 值”對(duì)組成,每行一對(duì),關(guān)鍵字與值使用英文 “:” 分割 請(qǐng)求體:請(qǐng)求參數(shù),并不是所有的請(qǐng)求有又請(qǐng)求參數(shù)。一般 get 參數(shù) 的格式 name=tom&password=1234&realName=tomson,也可以將參數(shù)放在 body 里面。
傳輸層:TCP 傳輸報(bào)文
網(wǎng)絡(luò)層:IP 協(xié)議查詢 MAC 地址
鏈路層:以太網(wǎng)協(xié)議
標(biāo)頭:數(shù)據(jù)包的發(fā)送者、接受者、數(shù)據(jù)類型 數(shù)據(jù):數(shù)據(jù)包具體內(nèi)容
Mac 地址
三次握手

四次揮手
其實(shí)是客戶端在發(fā)送 [FIN] 報(bào)文的時(shí)候順帶發(fā)了一個(gè) [ACK] 確認(rèn)上次傳輸確認(rèn)。 接著服務(wù)端通過(guò) 80 端口響應(yīng)了 [ACK] ,然后立馬響應(yīng) [FIN, ACK] 表示數(shù)據(jù)傳輸完了,可以關(guān)閉連接。 最后瀏覽器通過(guò) 13743 端口 發(fā)送 [ACK] 包給服務(wù)端,客服端與服務(wù)端連接就關(guān)閉了。


SYN_SENT - 客戶端發(fā)起第 1 次握手后,連接狀態(tài)為 SYN_SENT ,等待服務(wù)端內(nèi)核進(jìn)行應(yīng)答,如果服務(wù)端來(lái)不及處理(例如服務(wù)端的 backlog 隊(duì)列已滿)就可以看到這種狀態(tài)的連接。 ESTABLISHED - 表示連接處于正常狀態(tài),可以進(jìn)行數(shù)據(jù)傳送??蛻舳耸盏椒?wù)器回復(fù)的 SYN+ACK 后,對(duì)服務(wù)端的 SYN 單獨(dú)回復(fù)(第 3 次握手),連接建立完成,進(jìn)入 ESTABLISHED 狀態(tài)。服務(wù)端程序收到第 3 次握手包后,也進(jìn)入 ESTABLISHED 狀態(tài)。 FIN_WAIT_1 - 客戶端發(fā)送了關(guān)閉連接的 FIN 報(bào)文后,等待服務(wù)端回復(fù) ACK 確認(rèn)。 FIN_WAIT_2 - 表示我方已關(guān)閉連接,正在等待服務(wù)端關(guān)閉??蛻舳税l(fā)了關(guān)閉連接的 FIN 報(bào)文后,服務(wù)器發(fā)回 ACK 應(yīng)答,但是沒(méi)進(jìn)行關(guān)閉,就會(huì)處于這種狀態(tài)。 TIME_WAIT - 雙方都正常關(guān)閉連接后,客戶端會(huì)維持 TIME_WAIT 一段時(shí)間,以確保最后一個(gè) ACK 能成功發(fā)送到服務(wù)器端。停留時(shí)長(zhǎng)為 2 倍的 MSL (報(bào)文最大生存時(shí)間),Linux 下大約是 60 秒。所以在一個(gè)頻繁建立短連接的服務(wù)器上通??梢钥吹匠汕先f(wàn)的 TIME_WAIT 連接。
LISTEN - 表示當(dāng)前程序正在監(jiān)聽(tīng)某個(gè)端口時(shí)。 SYN_RCVD - 服務(wù)端收到第 1 次握手后,進(jìn)入 SYN_RCVD 狀態(tài),并回復(fù)一個(gè) SYN+ACK(第 2 次握手),再等待對(duì)方確認(rèn)。 ESTABLISHED - 表示連接處于正常狀態(tài),可以進(jìn)行數(shù)據(jù)傳送。完成 TCP3 次握手后,連接建立完成,進(jìn)入 ESTABLISHED 狀態(tài)。 CLOSE_WAIT - 表示客戶端已經(jīng)關(guān)閉連接,但是本地還沒(méi)關(guān)閉,正在等待本地關(guān)閉。有時(shí)客戶端程序已經(jīng)退出了,但服務(wù)端程序由于異?;?BUG 沒(méi)有調(diào)用 close()函數(shù)對(duì)連接進(jìn)行關(guān)閉,那在服務(wù)器這個(gè)連接就會(huì)一直處于 CLOSE_WAIT 狀態(tài),而在客戶機(jī)已經(jīng)不存在這個(gè)連接了。 LAST_ACK - 表示正在等待客戶端對(duì)服務(wù)端的關(guān)閉請(qǐng)求進(jìn)行最終確認(rèn)。
可靠地實(shí)現(xiàn) TCP 全雙工連接的終止 在進(jìn)行關(guān)閉連接四路握手協(xié)議時(shí),最后的 ACK 是由主動(dòng)關(guān)閉端發(fā)出的,如果這個(gè)最終的 ACK 丟失,服務(wù)器將重發(fā)最終的 FIN,因此客戶端必須維護(hù)狀態(tài)信息允 許它重發(fā)最終的 ACK。如 果不維持這個(gè)狀態(tài)信息,那么客戶端將響應(yīng) RST 分節(jié),服務(wù)器將此分節(jié)解釋成一個(gè)錯(cuò)誤( 在 java 中會(huì)拋出 connection reset 的 SocketException)。因而,要實(shí)現(xiàn) TCP 全雙工連接的正常終 止,必須處理終止序列四個(gè)分節(jié)中任何一個(gè)分節(jié)的丟失情況,主動(dòng)關(guān)閉 的客戶端必須維持狀 態(tài)信息進(jìn)入 TIME_WAIT 狀態(tài)。 允許老的重復(fù)分節(jié)在網(wǎng)絡(luò)中消逝 TCP 分節(jié)可能由于路由器異常而“迷途”,在迷途期間,TCP 發(fā)送端可能因確認(rèn)超時(shí)而重發(fā)這個(gè) 分節(jié),迷途的分節(jié)在路由器修復(fù)后也會(huì)被送到最終目的地,這個(gè) 原來(lái)的迷途分節(jié)就稱為 lost duplicate。在關(guān)閉一個(gè) TCP 連接后,馬上又重新建立起一個(gè)相同的 IP 地址和端口之間的 TCP 連接,后一個(gè)連接被稱為前一個(gè)連接的化身 ( incarnation),那么有可能出現(xiàn)這種情況,前一 個(gè)連接的迷途重復(fù)分組在前一個(gè)連接終止后出現(xiàn),從而被誤解成從屬于新的化身。為了避免 這個(gè)情 況,TCP 不允許處于 TIME_WAIT 狀態(tài)的連接啟動(dòng)一個(gè)新的化身,因?yàn)?TIME_WAIT 狀 態(tài)持續(xù) 2MSL,就可以保證當(dāng)成功建立一個(gè) TCP 連接的時(shí) 候,來(lái)自連接先前化身的重復(fù)分組已 經(jīng)在網(wǎng)絡(luò)中消逝。
保證 TCP 協(xié)議的全雙工連接能夠可靠關(guān)閉; 保證這次連接的重復(fù)數(shù)據(jù)段從網(wǎng)絡(luò)中消失,防止端口被重用時(shí)可能產(chǎn)生數(shù)據(jù)混淆;
?
服務(wù)器處理請(qǐng)求并響應(yīng) HTTP 報(bào)文

起始行(Start Line):描述請(qǐng)求或者響應(yīng)的基本信息。 Header:使用 key-value 的形式詳細(xì)說(shuō)明報(bào)文信息。 空行。 消息正文(Entity):傳輸?shù)臄?shù)據(jù),圖片、視頻、文本等都可以。


GET、POST、HEAD、PUT、DELETE、OPTIONS、TRACE、CONNECT。GET / HTTP/1.1 翻譯成文字大概就是:“hello,服務(wù)器,我要請(qǐng)求根目錄下的默認(rèn)文件使用的是 HTTP 1.1 協(xié)議版本”。header 字段不區(qū)分大小寫,通常是首字母大寫; 字段名不允許有空格,可以使用 “-”,不能使用 “_”; 字段名必須緊接著 “:”,不能有空格,但是 “:” 后面可以有空格。 字段名順序沒(méi)有意義;
?
瀏覽器接收響應(yīng)并渲染數(shù)據(jù)
根據(jù) HTML 解析 DOM 樹; 根據(jù) CSS 解析出 CSS 規(guī)則樹; 結(jié)合 DOM 樹與 CSS 規(guī)則樹,生成渲染樹; 根據(jù)生成的渲染樹計(jì)算每個(gè)節(jié)點(diǎn)的信息; 根據(jù)節(jié)點(diǎn)信息繪制畫面展示給用戶。

有道無(wú)術(shù),術(shù)可成;有術(shù)無(wú)道,止于術(shù)
歡迎大家關(guān)注Java之道公眾號(hào)
好文章,我在看??
