摘要:但收到此失效的連接請求報文段后,就誤認為是再次發出的一個新的連接請求。采用三次握手的辦法可以防止上述現象發生。
概覽
日期:2018-4-26
目標:了解從輸入URL到頁面加載完成的過程中都發生了什么事情
總用時:一天
完成情況:達成
為什么會想要了解從輸入URL到頁面加載完成的過程中都發生了什么事情這個問題呢,因為課程參考資料的Web 建站技術中HTML、HTML5、XHTML、CSS、SQL、JavaScript、PHP、ASP.NET、Web Services 是什么中最高票答案中給出了下圖所示的網站訪問基本過程,張秋怡學姐的解答也十分易懂:
再者這個問題可謂是常見的面試題之一,而這張圖中只是給出了非常基本的一個前后端交互的過程,由于自己有基礎,所以列出的相關概念也都基本理解了,于是就花些時間擴展一下
跟我一起來學起來我們在打開瀏覽器,然后在輸入URL的時候有沒有發現瀏覽器會給你一些你似曾相識且與你輸入的內容相匹配的網址呢?
其實我們在瀏覽器中輸入URL的時候,瀏覽器就會開始智能的匹配可能URL,瀏覽器會從歷史記錄,書簽等地方,找到你已經輸入的字符串可能對應的URL,然后給出智能提示
在輸好URL后我們會按下Enter鍵,瀏覽器會發起請求,如果URL是域名而不是IP地址,將進行域名解析,所謂域名解析是指什么呢?
IP地址是網絡上標識站點的數字地址,為了方便記憶,采用域名來代替IP地址標識站點地址,域名解析就是域名到IP地址的轉換過程。
域名解析按下面的步驟進行(部分內容涉及到計算機網絡知識):
我們本地硬盤下有一個hosts(windows下路徑為C:WindowsSystem32driversetc)文件,作用是將一些常用的網址域名與其對應的IP地址建立一個關聯“數據庫”。一般來說,系統會首先自動從hosts文件中尋找對應的IP地址,如果有的話就直接使用hosts文件里面的IP地址,然后直接進行端口確認
如果上一步沒有找到,瀏覽器將調用解析程序,并成為DNS服務器的一個客戶,把待解析的域名放在DNS請求報文中,以UDP用戶數據報的方式發給本地DNS服務器
如果本地DNS服務器查找到相應的域名的IP地址,就把對應的IP地址放在回答報文中返回
如果上一步沒有找到,即本地DNS服務器不知道被查詢域名的IP地址,由于主機向本地DNS服務器的查詢是遞歸查詢,所以此時,本地DNS服務器就會以DNS客戶的身份向其他根DNS服務器繼續發出查詢請求報文。本地DNS服務器向根DNS服務器的查詢是迭代查詢,當找到相應域名的IP地址后,就會把這個結果返回給最初發起查詢請求的瀏覽器
遞歸查詢:在該模式下DNS服務器接收到客戶機請求,必須返回一個準確的查詢結果給客戶機。如果該DNS服務器本地沒有存儲被查詢的DNS信息,那么該服務器會(替客戶機)詢問其他服務器,并將返回的查詢結果再返回給客戶機。
迭代查詢:在該模式下DNS服務器接收到客戶機請求,如果該DNS服務器本地沒有存儲被查詢的DNS信息,DNS服務器會向客戶機提供其他能夠解析查詢請求的DNS服務器地址,讓客戶機再向這臺DNS服務器提交請求,依次循環直到返回查詢的結果為止。
經過上面的步驟后,瀏覽器已經獲得輸入域名的IP地址,可以進行下一步了。
瀏覽器得到IP地址后,還要確認一下端口,默認端口是80端口,一個服務器可能會提供不同的服務,這些服務通過端口來區分,可以指定端口號
瀏覽器得到IP地址并確認端口后,會向目標服務器發起HTTP請求,HTTP請求是通過TCP連接來發送的(如果是HTTPS則需要先建立SSL連接,再是TCP連接,下面的討論基于HTTP),具體如下
瀏覽器會生成目標服務器的HTTP請求報文,請求報文一般包含請求方法、請求URI、協議版本、請求首部字段等內容,HTTP請求準備好后,HTTP請求報文從應用層傳到傳輸層后會被分割為報文段,并會發起一條到達目標服務器的TCP連接,開始TCP三次握手,過程如圖所示:
通俗的可以理解為:
A主動向B打電話:嗨,能聽到嗎(SYN=1,seq=x),然后A就開始等待B的回答(SYN-SENT狀態),此時A不知道B能不能聽到
B聽到A的話之后,可以確認它能聽到A,但是它還要確認一下A能不能聽到他自己的聲音,于是B說:我能聽到你的聲音(ACK=1,ack=x+1),你能聽到我的聲音嗎(SYN=1,seq=y),然后B開始等待A的恢復(SYN-RECD狀態)
A聽到B的話之后,A可以確認兩件事,一是B能聽到它說話,二是它也能聽到B說話,A已經可以隨時說話和傾聽了(ESTABLISHED狀態)。但是此時的B還在等待中,并不知道A能不能聽到,所以此時A需要再回復B說:我可以聽到你的聲音(ACK=1,ack=y+1),開始愉快的聊天吧~(seq=x+1),B聽到這句話后便也可以隨時說話和傾聽了(ESTABLISHED狀態)
之后兩個人就可以balabalabala....
HTTP請求的請求報文是直接附在第三次握手的消息中
穿插補充小知識,為什么是三次握手,而不是兩次四次?
有一種觀點是三次握手是基于TCP協議的可靠性(Reliability)要求,這是確認雙發都能進行收發的最小次數,兩次確認不了,四次多余。但是并沒有完全意義上的可靠,不論握手多少次都只能表明握手的時候是可靠的,不能保證后面數據傳輸時一直可靠,因為信道是不可靠的,當然三次握手至少可以表明它曾經可靠,這是兩次握手無法完成的,而四次甚至更多次握手僅僅是提高“它曾經可靠”這個結論的可信程度。所以這個握手也只是確保可靠的一個基本需要,TCP協議的可靠性(注意區分完整性integrity)更多的是由校驗和、定時器超時重傳、確認機制在《計算機網絡》一書中也有講過這個問題,給出的解釋是:三次握手是為了防止失效的連接請求報文段被服務端接收,從而產生錯誤。具體例子如下所述:
client發出的一個連接請求報文段并沒有丟失,而是在某個網絡結點長時間的滯留了,以致延誤到連接釋放以后的某個時間才到達server。本來這是一個早已失效的報文段。但server收到此失效的連接請求報文段后,就誤認為是client再次發出的一個新的連接請求。于是就向client發出確認報文段,同意建立連接。
假設不采用“三次握手”,那么只要server發出確認,新的連接就建立了。但是由于現在client并沒有發出建立連接的請求,因此不會理睬server的確認,也不會向server發送數據。而server卻以為新的連接已經建立,并一直等待client發來數據。這樣,server的很多資源就白白浪費掉了。
采用“三次握手”的辦法可以防止上述現象發生。例如剛才那種情況,client不會向server的確認發出確認。server由于收不到確認,就知道client并沒有要求建立連接
連接建立之后,開始進行數據傳輸,雖然瀏覽器知道目標服務器的IP和端口,但是數據總不可能飛過去吧?HTTP請求報文段會從傳輸層傳到網絡層,在網絡層被封裝成IP數據包,網絡層規定了通過怎樣的路徑(所謂的傳輸路線)到達目標服務器,并把數據包傳送給對方。
網絡層封裝好的IP數據包會進一步傳到下一層 --- 數據鏈路層,然后會再次被封裝到MAC數據幀結構中,由于IP地址間的通信依賴于MAC地址(網卡所屬的固定地址),所以MAC數據幀結構中會有經過ARP協議解析后的MAC地址(不一定是目標服務器的MAC地址,因為實際上通信的雙方在同一局域網(LAN)內的情況是很少的,一般都會經過路由中轉)。
數據鏈路層的MAC數據幀再向下傳,便會到達物理層,這里要注意物理層考慮的是怎樣才能在連接各種計算機的傳輸媒體上傳輸數據比特流,而不是指具體的傳輸媒體。 物理層需要確保原始的數據可在各種物理媒體上傳輸,它規定了傳輸媒體的機械特性、電氣特性、功能特性、過程特性:
常見的傳輸媒體有雙絞線、電纜、光纜、無線信道等,物理層的任務就是要讓數據在這些傳輸媒體上都能能進行傳輸
通過MAC地址匹配,數據通過傳輸媒體到達目標服務器的物理層,物理層接收數據比特流然后向上傳送到服務器的數據鏈路層,在數據鏈路層MAC數據幀將進行封裝的逆操作,還原成IP數據包之后向上傳送到網絡層,網絡層也進行封裝的逆操作還原成HTTP請求報文段(分割后的一小段一小段的),然后這些報文段向上傳到傳輸層,在傳輸層按原來的序號重新組裝成完整的HTTP請求報文,再向上傳到應用層,應用層的HTTP協議便會開始對請求進行處理
這個處理可能是直接返回靜態的資源,也可能經過PHP、JAVA等語言進行處理等,等處理完成后,會返回一個HTTP響應,它生成一個HTTP響應報文,與HTTP請求報文結構類似,然后這個響應報文會“走過”請求報文來時的路到達瀏覽器
瀏覽器接收HTTP響應,然后有可能釋放TCP連接,也有可能重新使用這個TCP連接發送新的請求(持久連接),此處了解一下TCP連接的釋放,不同于TCP連接建立的三次握手,TCP連接的釋放是四次揮手,客戶端和服務器端都可以發起關閉請求,也存在兩者同時發起關閉請求的情況,圖中為客戶端A主動發起關閉請求:
同樣通俗的解釋一波:
A對B要傳的文件已經傳完了,于是他對B說:我要傳的文件已經傳完了,我要準備下線了(seq=u,FIN=1)。然后A就等待B的回復(FIN-WAIT-1狀態)
B看到A的消息后,回復A說:知道了,但是我還有文件給你(ACK=1,ack=u+1,seq=v)。B進入等他文件傳完的狀態(CLOSE-WAIT狀態)。
A收到B的回復之后,下線不了了,于是繼續等待著B的文件傳完(FIN-WAIT-2狀態)
幾分鐘后,B的文件傳完了,此時他對A說:我的文件傳完了,我也要下線了(seq=w,FIN=1,ACK=1,ack=u+1),然后B等待A的回復來確認真的可以下線了(LAST-ACK狀態)
A收到B的回復后,便對A說:好的,那你下線吧(ACK=1,seq=u+1,ack=w+1)。此時A會等待一段時間(2MSL,TIME-WAIT狀態),B收到后就直接下線了(CLOSE狀態),然后2MSL時間到了之后,A也下線(CLOSE狀態)
為什么服務器B在接到A的斷開請求時不立即同意斷開?
當服務器B收到斷開連接的請求時,服務器可能仍然有數據未發送完畢,所以服務器先發送確認信號,等所有數據發送完畢后再同意斷開
為什么是四次揮手,而不是像建立連接一樣的三次
因為TCP連接是全雙工模式,服務器B收到A的斷開請求時,僅僅表明A沒有東西傳給服務器B了,但此時服務器B可能向A的傳輸還沒結束,所以服務器B要先給A一個確認收到A的斷開請求的ACK報文,然后繼續向A把信息傳完,等傳完之后服務器B再向A發送斷開請求的報文段,等A收到并回復ACK報文后再釋放連接。
也就是說對于A來說他要發送請求給B并等待B確認,對于B來說也要發送請求給A并等待A確認,兩者都經過這兩個過程才能完全釋放TCP連接,而非單方面的釋放。
建立連接只需要建立,沒有數據的影響,而釋放連接還要考慮數據是否傳輸完,所以建立連接的時候B確認收到A的建立請求與B發送建立請求這一步可以合成一步成為TCP建立連接的第二次握手,而釋放連接時卻必須分開。
最后一次握手后A為什么要等2MSL?
首先解釋一下MSL,MSL是指最長報文段壽命,RFC793建議為兩分鐘,但實際上可據實際情況而定,也就是說一個報文段最久可存在的時間是MSL
這是為了保證A發送的最后一個ACK報文能夠到達服務器B,如果這個ACK報文丟失了,服務器B沒有收到,B會超時重傳第三次握手的FIN+ACK報文給A,這個時候處于等待的A就可以收到這個重傳的FIN+ACK報文,并再次發送ACK報文給服務器B,并且重新啟動2MSL計時器,最終結果是A和B都正常進入CLOSE狀態。如果A發完ACK報文后就直接釋放了A-->B的連接,那么A就收不到B重傳的FIN+ACK報文,也不能重新發送ACK`報文,那么B就無法按正常步驟釋放B-->A的連接
防止“已失效的連接請求報文”出現在下一個新的連接中,因為一個報文段的壽命是MSL,所以A在發送完最后一個ACK報文段之后,再經過時間2MSL,本連接持續的時間內所產生的所有報文段都將在網絡中消失,這樣這些舊的報文段便不會出現在下一個新的連接中
瀏覽器之后會檢查HTTP的響應狀態,主要通過響應碼來判斷
1xx: 表示通知信息的,比如請求收到了或正在處理
2xx:表示成功,操作被成功接收并處理
3xx:表示重定向,一般完成請求還必須采取進一步的行動
4xx:表示客戶端的差錯
5xx:表示服務器的差錯
如果響應可緩存,瀏覽器將把響應存入緩存
瀏覽器根據HTTP報頭信息解碼響應,決定如何處理這些響應,并展現響應,以響應為一個HTML為例
瀏覽器開始自上而下,自左而右的加載HTML文檔,最開始會遇到聲明,然后根據聲明瀏覽器就知道該用哪種規范來解析這個文檔
再繼續邊加載邊解析,邊生成DOM樹,加載過程中遇到外部CSS文件,瀏覽器便會另外發出一個請求,來獲取CSS文件(過程和上面說的一樣),獲取CSS后會生成CSS Rule樹。DOM樹和CSS Rule樹生成Render樹,頁面可以開始邊加載邊渲染了
渲染樹和DOM樹的關系:那些不可見的DOM元素(如…,display=none的元素)不會被插入渲染樹中;還有像一些節點是絕對定位或浮動,這些節點會在文本流之外,因此他們會在渲染樹和DOM樹的不同位置,渲染樹標識出真實的位置,并用一個占位結構標識出他們原來的位置,而DOM樹上是他們原來的位置
渲染包含"布局"(layout)和"繪制"(paint)這兩個步驟,所謂"布局"是指給出每個DOM節點在瀏覽器窗口中的準確位置,"繪制"是指遍歷Render樹將布局好的DOM節點繪制在屏幕上。
瀏覽器繼續加載渲染,如果遇到<script>標簽,瀏覽器會立即執行(暫不考慮defer及async屬性),此時會出現頁面阻塞,不僅要等待文檔中JS文件下載加載完畢,還要等待JS解析執行完畢,才可以恢復HTML文檔的加載解析。
這是瀏覽器為了防止出現JS修改DOM樹,需要重新構建DOM樹的情況,DOM樹改變瀏覽器需要回過頭來重新渲染這部分代碼,所以瀏覽器希望通過阻塞其他內容的下載和呈現,來避免出現更多的不必要的Reflow(稱為回流或者重排)
如果放在的中,則標簽無法被加載,那么頁面自然就無法渲染了,因此這將導致在該JS代碼完全執行完之前,頁面都是一片空白,用戶體驗非常不好,一般我看到長時間的空白頁面,我都非常想直接關閉它。因此會推薦將所有標簽盡可能放到標簽的底部,以盡量減少對整個頁面下載的影響,此時雖然還會存在一個腳本阻塞另一個腳本的問題,但是用戶體驗比上面的好很多,因為用戶看到了大部分內容,而不是空白
defer屬性相當于告訴瀏覽器立即下載,延遲執行。它使得加載后續文檔元素的過程將和JS文件的加載并行進行(異步),但是JS文件的執行要在整個頁面解析完成之后,DOMContentLoaded事件觸發之前完成,執行順序為出現的先后順序。(高程中指出現實中不一定會按照順序執行,也不一定會在DOMContentLoaded事件觸發之前完成,因此最好只包含一個延遲腳本,這可能是與瀏覽器的實現有關,具體什么情況下會出現我還不知道???)
async屬性相當于告訴瀏覽器立即下載執行,并且頁面的加載渲染不需要等待該腳本加載和執行,它們兩者會異步進行。標記為async的腳本不會按照它們出現的先后順序執行,而是誰先下載完了誰就先執行,它們一定會在頁面的load事件觸發之前執行,但可能會在DOMContentLoaded事件觸發之前或之后執行。基于前面所說的一點原因,異步腳本最好不要修改DOM,如果由多個異步腳本,它們之間最好沒有依賴關系
瀏覽器繼續加載渲染,如果遇到圖片資源,瀏覽器也會另外發出一個請求,來獲取圖片資源,這是異步請求,所以不會等到圖片下載完,而是繼續渲染后面的HTML文檔。
等到服務器返回圖片文件,如果先前并沒有為這個圖片設定寬高,那么由于圖片占用了一定面積,影響了后面段落的排布,瀏覽器會進行Reflow
然后然后終于和</html>碰面了,此次的頁面加載渲染過程完成,瀏覽器也是很累了,然后會立即觸發DOMContentLoaded事件,該事件是在形成完整的DOM樹之后就會觸發,而不會理會圖像、JS文件、CSS文件或其他資源是否已經下載完畢
當頁面完全加載后,也就是所有圖像、JS文件、CSS文件等外部資源都加載完成后會觸發load事件
用戶在頁面上進行交互時,可能會導致頁面進行Repaint或Reflow
Repaint:如果只是改變了某個元素的背景顏色,文字顏色等,不影響元素周圍或內部布局的屬性,將只會引起瀏覽器的Repaint,重繪某一部分
Reflow:如果某個部分發生了的變化影響了布局,那瀏覽器就需要倒回去重新渲染,每次Reflow必然會導致Repaint
尾聲本來只是想了解了解,結果一入深似海,看似簡單的操作背后藏著數不清的小動作,文中也只是涉及了一部分,還有很多相關的過程沒有涉及到,但是能力有限,還是慢慢來,暫時就先告一段落,文中如有錯誤還請指正哦~
參考Web 建站技術中HTML、HTML5、XHTML、CSS、SQL、JavaScript、PHP、ASP.NET、Web Services 是什么
TCP 為什么是三次握手,而不是兩次或四次?
How browsers work
《計算機網絡第六版》--謝希仁
《JavaScript高級程序設計第三版》
《圖解HTTP》
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/52260.html
摘要:但收到此失效的連接請求報文段后,就誤認為是再次發出的一個新的連接請求。采用三次握手的辦法可以防止上述現象發生。 概覽 日期:2018-4-26目標:了解從輸入URL到頁面加載完成的過程中都發生了什么事情總用時:一天完成情況:達成 基本過程 為什么會想要了解從輸入URL到頁面加載完成的過程中都發生了什么事情這個問題呢,因為課程參考資料的Web 建站技術中HTML、HTML5、XHTML、...
摘要:第一個問題從輸入到瀏覽器接收的過程中發生了什么事情從觸屏到首先是輸入,大部分人的第一反應會是鍵盤,不過為了與時俱進,這里將介紹觸摸屏設備的交互。 第一個問題:從輸入 URL 到瀏覽器接收的過程中發生了什么事情?從觸屏到 CPU 首先是「輸入 URL」,大部分人的第一反應會是鍵盤,不過為了與時俱進,這里將介紹觸摸屏設備的交互。 觸摸屏一種傳感器,目前大多是基于電容(Capacitive)...
閱讀 2809·2021-10-08 10:04
閱讀 3198·2021-09-10 11:20
閱讀 522·2019-08-30 10:54
閱讀 3305·2019-08-29 17:25
閱讀 2301·2019-08-29 16:24
閱讀 883·2019-08-29 12:26
閱讀 1446·2019-08-23 18:35
閱讀 1930·2019-08-23 17:53