前言
過年倒計時~
今天是網絡篇的最后一篇,網絡知識也是面試常考內容,所以必須要把基礎知識打牢。
網絡十二問,送給大家。
這些問題,你能答上來嗎
我總結了下網絡方面會涉及到的一些問題,大家看看,如果都能答上來,那這篇文章就可以略過了。
- 網絡通信的過程,以及中間用了什么協議?
- TCP連接過程,三次握手和四次揮手,為什么?
- 常用的狀態碼。
- 講一下TCP協議和UDP協議的區別和場景
- socket和WebSocket
- Https的鏈接建立過程
- 講解一下數字簽名,為什么真實可靠
- 證書鏈安全機制
- 建立過程耗時,那么怎么優化呢?
- 講一下Http和Https的區別
- Http傳輸圖片有哪些方式
- 怎么實現分塊傳輸,斷點續傳?
網絡通信的過程,以及中間用了什么協議
這個問題我之前專門做了一個動畫,大家可以翻到上一篇文章看看:
再簡單總結下:
客戶端:
- 1、在瀏覽器輸入網址
- 2、瀏覽器解析網址,並生成
http
請求消息 - 3、瀏覽器調用系統解析器,發送消息到DNS服務器查詢域名對應的
ip
- 4、拿到ip后,和請求消息一起交給操作系統協議棧的
TCP模塊
- 5、將數據分成一個個數據包,並加上TCP報頭形成
TCP數據包
- 6、TCP報頭包括發送方端口號、接收方端口號、數據包的
序號、ACK號
。 - 7、然后將
TCP消息
交給IP模塊。 - 8、IP模塊會添加
IP頭部
和MAC頭部
。 - 9、IP頭部包括
IP地址
,為IP模塊使用,MAC頭部包括MAC地址,為數據鏈路層使用。 - 10、
IP模塊
會把整個消息包交給網絡硬件,也就是數據鏈路層,比如以太網,WIFI等 - 11、然后網卡會將這些包轉換成
電信號或者在光信號
,通過網線或者光纖發送出去,再由路由器等轉發設備送達接收方。
服務器端:
- 1、數據包到達服務器的
數據鏈路層
,比如以太網,然后會將其轉換為數據包(數字信號)交給IP模塊
。 - 2、
IP模塊
會將MAC頭部和IP頭部后面的內容,也就是TCP數據包發送給TCP模塊。 - 3、
TCP模塊
會解析TCP頭信息,然后和客戶端溝通表示收到這個數據包了。 - 4、
TCP模塊
在收到消息的所有數據包之后,就會封裝好消息,生成相應報文發給應用層,也就是HTTP層。 - 5、
HTTP層
收到消息,比如是HTML數據,就會解析這個HTML數據,最終繪制到瀏覽器頁面上。
TCP連接過程,三次握手和四次揮手,為什么?
連接階段(三次握手):
- 創建套接字
Socket
,服務器會在啟動的時候就創建好,客戶端是在需要訪問服務器的時候創建套接字 - 然后發起連接操作,其實就是Socket的
connect
方法 - 這時候客戶端會生成一個TCP數據包。這個數據包的TCP頭部有幾個重要信息:
SYN、ACK、Seq、Ack
。
SYN,同步序列編號,是TCP/IP建立連接時使用的握手信號,如果這個值為1就代表是連接消息。
ACK,確認標志,如果這個值為1就代表是確認消息。
Seq,數據包序號,是發送數據的一個順序編號。
Ack Number,確認數字號,是接收數據的一個順序編號。
- 所以客戶端就生成了這樣一個數據包,其中頭部信息的控制位
SYN
設置為1,代表連接。SEQ
設置一個隨機數,代表初始序號,比如100。 - 然后服務器端收到這個消息,知道了客戶端是要來連接的
(SYN=1)
,知道了傳輸數據的初始序號(SEQ=100)
。 - 服務器端也要生成一個數據包發送給客戶端,這個數據包的TCP頭部會包含:表示我也要連接你的
SYN(SYN=1)
,我已經收到了你的上個數據包的確認號ACK=1(Ack=Seq+1=101)
,以及服務器端隨機生成的一個序號Seq(比如Seq=200)
。 - 最后客戶端收到這個消息后,表示客戶端到服務器的連接是無誤了,然后再發送一個數據包表示也確認收到了服務器發來的數據包,這個數據包的頭部就主要就是一個
ACK=1(Ack=Seq+1=201)
。 - 至此,連接成功,三次握手結束,后面數據就會正常傳輸,並且每次都要帶上TCP頭部中的
Seq和Ack
。
這里有個問題是關於為什么需要三次握手
?
最主要的原因就是需要通信雙方都確認自己的消息被准確傳達過去了。
A發送消息給B,B回一條消息表示我收到了,這個過程就保證了A的通信能力。
B發送消息給A,A回一條消息表示我收到了,這個過程就保證了B的通信能力。
也就是四條消息能保證雙方的消息發送都是正常的,其中B回消息和B發消息,可以融合為一次消息,所以就有了三次握手
。
數據傳輸階段:
數據傳輸階段有個改變就是Ack確認號
不再是Seq+1
了,而是Seq+數據長度
。例如:
- A發送給B的數據包(Seq=100,長度=1000字節)
- B回給A的數據包(Ack=100+1000=1100)
這就是一次數據傳輸的頭部信息,Ack
代表下個數據包應該從哪個字節開始所以等於上個數據包的Seq+長度,Seq就等於上個數據包的Ack。
當然,TCP通信是雙向的,所以實際數據每個消息都會有Seq和Ack
:
- A發送給B的數據包(Ack=200,Seq=100,長度=1000字節)
- B回給A的數據包(Ack=100+1000=1100,Seq=上一個數據包的Ack=200,長度=500字節)
- A發送給B數據包(Seq=1100,Ack=200+500=700)
斷開階段(四次揮手):
和連接階段一樣,TCP頭部也有一個專門用作關閉連接的值叫做FIN。
-
客戶端准備關閉連接,會發送一個
TCP數據包
,頭部信息中包括(FIN=1代表要斷開連接)
。 -
服務器端收到消息,回復一個數據包給客戶端,頭部信息中包括
Ack確認號
。但是此時服務器端的正常業務可能沒有完成,還要處理下數據,收個尾。 -
客戶端收到消息。
-
服務器繼續處理數據。
-
服務器處理數據完畢,准備關閉連接,會發送一個
TCP數據包
給客戶端,頭部信息中包括(FIN=1代表要斷開連接) -
客戶端端收到消息,回復一個數據包給服務器端,頭部信息中包括
Ack確認號
。 -
服務器收到消息,到此服務器端完成連接關閉工作。
-
客戶端經過一段時間(2MSL),自動進入
關閉狀態
,到此客戶端完成連接關閉工作。
MSL 是 Maximum Segment Lifetime,報文最大生存時間,它是任何報文在網絡上存在的最長時間,超過這個時間報文將被丟棄。
這里有個問題是關於為什么需要四次揮手?
A發送斷開消息給B,B回一條消息表示我收到了,這個過程就保證了A斷開成功。
B發送斷開消息給A,A回一條消息表示我收到了,這個過程就保證了B斷開成功。
其實和連接階段的區別就在於,這里的B的確認消息和斷開消息不能融合
。因為A要斷開的時候,B可能還有數據要處理要發送,所以要等正常業務處理完,在發送斷開消息。
常用的狀態碼
1XX
- 臨時消息。服務器收到請求,需要請求者繼續操作。2XX
- 請求成功。請求成功收到,理解並處理。3XX
- 重定向。需要進一步的操作以完成請求。4XX
- 客戶端錯誤。請求包含語法錯誤或無法完成請求。5XX
- 服務器錯誤。服務器在處理請求的過程中發生了錯誤。
常見狀態碼:
200 OK
- 客戶端請求成功
301
- 資源(網頁等)被永久轉移到其它URL
302
- 臨時跳轉
400 Bad Request
- 客戶端請求有語法錯誤,不能被服務器所理解
404 - 請求資源不存在
,錯誤的URL。
500
- 服務器內部發生了不可預期的錯誤。
503 Server Unavailable
- 服務器當前不能處理客戶端的請求,一段時間后可能恢復正常。
講一下TCP協議和UDP協議的區別和場景
我先說兩個場景,大家可能就比較能理解了。
1) 第一個場景,瀏覽網頁
。(TCP場景)
- 我們訪問網頁,網頁肯定要把所有數據都正確的顯示出來吧,如果這個過程中丟包了,那么肯定也會重新傳包,不可能只顯示一部分網頁(保證數據正確性)
- 同樣,網頁中的內容肯定也需要是
順序
的。比如我一個抽獎,不可能還沒抽就把獎給你了。(保證數據的順序) - 再來,在這個對數據要求嚴格的過程中,我們肯定需要兩方建立起一個
可靠
的連接,也就是我們上述說到的要經過三次握手才開始傳輸數據,並且每次發數據包都需要回執(面向連接的) - 而這種連接中傳輸數據就是用的
字節流
,也就是有根管道,你想怎么傳數據都行,想怎么接受數據也都可以,只要在這一根管道里面。
所以這種需要數據准確、順序不能錯、要求穩定可靠
的場景就需要用到TCP。
2)第二個場景,打游戲。(UDP場景)
打游戲最最重要的就是即時,不然我這個技能發出去了你那邊還沒被打中,這就玩不了了。
- 所以
UDP
是需要保證數據的即時性
,而不保證每個數據包都正確接收到,即使丟包了,也不會去找丟的那個是什么包,因為要顯示當前時間的當前數據包。(不保證數據正確性和數據順序,可能會丟包) - 同樣,為了數據的即時性,
UDP
也就不會去建立連接了,不需要什么三次握手,每次你還要確認收沒收到。管你收沒收到,我只要快速把每個數據包丟給你就行了。(面向無連接的) - 因為是
無連接
的,所以就不需要用到字節流,直接每次丟一個數據報
給你,接收方也只能接受一個數據報(不能和其他發送方的數據報混淆)。(基於數據報的)
如果你還是有點暈,可以看看這篇文章(亞當和夏娃),很形象的比喻:
https://www.zhihu.com/question/51388497?sort=created
socket和WebSocket
雖然這兩個貨名字類似,但其實不是一個層級的概念。
-
socket
,套接字。上文說過了,在TCP建立連接的過程中,是調用了Socket的相關API,建立了這個連接通道。所以它只是一個接口,一個類。 -
WebSocket
,是和HTTP同等級,屬於應用層協議。它是為了解決長時間通信的問題,由HTML5規范引出,是一種建立在TCP協議基礎上的全雙工通信的協議,同樣下層也需要TCP建立連接,所以也需要socket。
科普:WebSocket在TCP連接建立后,還要通過Http進行一次握手,也就是通過Http發送一條GET請求消息給服務器,告訴服務器我要建立WebSocket連接了,你准備好哦,具體做法就是在頭部信息中添加相關參數。然后服務器響應我知道了,並且將連接協議改成WebSocket,開始建立長連接。
如果硬要說這兩者有關系,那就是WebSocket
協議也用到了TCP連接
,而TCP連接用到了Socket
的API。
Https的連接建立過程
說完了HTTP和TCP/IP,再說說HTTPS
。
上一篇文章說了HTTPS是怎么保證數據安全傳輸,鏈接🔗:https://mp.weixin.qq.com/s/dbmwBVxHkvQ0fzWaSdtPYg
其中主要就是用到了數字證書
。
現在完整看看Https連接建立(也叫TLS握手流程)
:
- 1、客戶端發送 Client Hello 數據包消息。
這個消息內容包括一個隨機數(randomC)
,加密族
(密鑰交換算法也就是非對稱加密算法、對稱加密算法、哈希算法),Session ID
(用作恢復回話)。
客戶端要建立通信,在TCP握手之后,會發送第一個消息,也叫Client Hello
消息。這個消息主要發了以上的一些內容,其中密文族就是把客戶端這邊支持的一些算法發給服務器,然后服務器拿來和服務器支持的算法一比較,就能得出雙方都支持的最優算法了。
- 2、服務器回復三個數據包消息: Server Hello,Certificate,Server Hello Done。
Server Hello
消息內容包括一個隨機數(randomS),比較后得出的加密族,Session ID(用作恢復回話)。
到現在,雙方已經有兩個隨機數了,待會再看看這兩個隨機數是干嘛的。然后加密算法剛才說過了,服務器協商出了三種算法並發回給客戶端。
Certificate
消息就是發送數字證書了。這里就不細說了。
Server Hello Done
消息就是個結束標志,表示已經把該發的消息都發給你了。
- 3、對稱密鑰生成過程
1)首先,客戶端會對發來的證書進行驗證
,比如數字簽名、證書鏈、證書有效期、證書狀態。
2)證書校驗完畢后,然后客戶端會用證書里的服務器公鑰加密發送一個隨機數 pre—master secret
,服務器收到之后用自己的私鑰解密。
3)到此,客戶端和服務器就都有三個隨機數了:randomC、randomS、pre—master secret。
4)然后客戶端和服務器端分別按照固定的算法,用三個隨機數生成對稱密鑰
。
- 4、生成Session ID
這一步和開始兩個hello消息中的Session ID
對應起來了。
會生成會話的id,如果后續會話斷開了,那么通過這個Session ID
就可以恢復對話,不需要重新進行發送證書、生成密鑰過程了。
- 5、用對稱密鑰傳輸數據
拿到對稱密鑰后,雙方就可以使用對稱密鑰加密解密數據,進行正常通信了。
擴展
:為什么要使用非對稱加密算法協商出對稱加密這種方法?
首先,網絡傳輸數據對傳輸的速度要求比較高,在保證安全的前提下,所以采用了對稱加密的方法,而不用耗時較多的非對稱加密算法。
其次,在確定對稱加密傳輸數據的前提下,如果傳輸對稱加密的密鑰是個涉及到安全的問題,所以就采用了安全性更高的非對稱加密算法,加上證書鏈機制,保證了傳輸對稱密鑰相關數據
的安全性。
請給我講解一下數字簽名,為什么真實可靠
數字簽名
,也就是上文中說的電子簽名,再簡單回顧下:
數字簽名,其實也是一種非對稱加密
的用法。
它的使用方法是:
A使用私鑰對數據的哈希值
進行加密,這個加密后的密文就叫做簽名
,然后將這個密文和數據本身傳輸給B。
B拿到后,簽名用公鑰
解密出來,然后和傳過來數據的哈希值做比較,如果一樣,就說明這個簽名確實是A簽的,而且只有A才可以簽,因為只有A有私鑰
。
反應實際情況就是:
服務器端將數據,也就是我們要傳的數據(公鑰),用另外的私鑰簽名
數據的哈希值,然后和數據(公鑰)
一起傳過去。
然后客戶端用另外的公鑰對簽名解密,如果解密數據和數據(公鑰)的哈希值一致,就能證明來源正確
,不是被偽造的。
來源可靠
。數字簽名只能擁有私鑰的一方才能簽名,所以它的存在就保證了這個數據的來源是正確的數據可靠
。hash值是固定的,如果簽名解密的數據和本身的數據哈希值一致,說明數據是未被修改的。
證書鏈安全機制
證書頒發機構(CA, Certificate Authority)即頒發數字證書的機構。是負責發放和管理數字證書的權威機構,並作為電子商務交易中受信任的第三方,承擔公鑰體系中公鑰的合法性檢驗的責任。
實際情況中,服務器會拿自己的公鑰以及服務器的一些信息傳給CA
,然后CA
會返回給服務器一個數字證書
,這個證書里面包括:
- 服務器的公鑰
- 簽名算法
- 服務器的信息,包括主機名等。
- CA自己的私鑰對這個證書的簽名
然后服務器將這個證書在連接階段傳給客戶端
,客戶端怎么驗證呢?
細心的小伙伴肯定知道,每個客戶端,不管是電腦、手機都有自帶的系統根證書
,其中就會包括服務器數字證書的簽發機構
。所以系統的根證書會用他們的公鑰
幫我們對數字證書的簽名進行解密,然后和證書里面的數據哈希值進行對比,如果一樣,則代表來源
是正確的,數據
是沒有被修改的。
當然中間人也是可以通過CA申請證書的,但是證書中會有服務器的主機名,這個主機名(域名、IP)
就可以驗證你的來源是來源自哪個主機。
擴展一下:
其實在服務器證書和根證書中間還有一層結構:叫中級證書
,我們可以任意點開一個網頁,點擊左上角的🔒按鈕就可以看到證書詳情:
可以看到一般完整的SSL/TLS
證書有三層結構:
第一層:根證書
。也就是客戶端自帶的那些,根證書都是自簽名,即用自己的公鑰和私鑰完成了簽名的制作和驗證。第二層:中級證書
。一般根證書是不會直接頒發服務器證書的,因為這種行為比較危險,如果發現錯誤頒發就很麻煩,需要涉及到跟證書的修改。所以一般會引用中間證書,根證書對中間證書進行簽名,然后中間證書再對服務器證書進行簽名,一層套一層。第三層:服務器證書
。也就是跟我們服務器相關的這個證書了。
建立過程耗時,那么怎么優化呢?
- 1、升級HTTP2.0
HTTP 2.0在2013年8月進行首次合作共事性測試。在開放互聯網上HTTP 2.0將只用於https://網址,而 http://網址將繼續使用HTTP/1,目的是在開放互聯網上增加使用加密技術,以提供強有力的保護去遏制主動攻擊
HTTP2
主要有以下特性:
-
二進制分幀
。數據使用二進制傳輸,相比於文本傳輸,更利於解析和優化。 -
多路復用
。同域名下所有通信都在單個連接上完成,單個連接也可以承載任意數量的雙向數據流。 -
頭部優化
。HTTP/2對消息頭采用HPACK(專為http/2頭部設計的壓縮格式)進行壓縮傳輸,能夠節省消息頭占用的網絡的流量。 -
2、利用SessionID
這一點剛才已經說過了,為了在斷開重連后,重復連接過程,所以使用SessionID
記錄會話id,然后就可以重新復用定位到哪個會話了。
從而減去了重復發送證書、生成密鑰過程。
- 3、TLS False Start
這是Google提出來的優化方案,具體做法是:
在TLS握手協商的第二個階段,也就是客戶端在驗證證書,發送了pre—master secret
之后,就直接把應用數據帶上,比如請求網頁數據。
然后服務器端收到pre—master secret
后,生成對稱密鑰,然后直接用對稱密鑰解密這個應用數據,並響應消息給客戶端。
其實就是把兩個步驟混合為一個步驟了,客戶端不需要等待服務器確認,再發送應用數據,而是直接在第二階段就和pre—master secret
一起發送給服務器端,減少了握手過程,從而減少了耗時。
- 4、OCSP Stapling
OCSP
是一種驗證檢查證書吊銷狀態(合法性)的在線查詢服務。
驗證證書的過程中有一步是驗證證書的合法性,我們可以讓服務器先通過OCSP
查詢證書是否合法,然后把這個結果和證書一起發送給客戶端,客戶端就不需要單獨驗證證書的合法性了,從而提高了TLS握手效率。這個功能就叫做OCSP Stapling。
擴展:
如果不考慮建立過程,從整個Https
傳輸過程考慮,又有哪些優化的點呢?
可以看看這篇文章介紹:https://www.cnblogs.com/evan-blog/p/9898046.html
講一下HTTP和HTTPS的區別
經過上面大篇幅的講解,對於兩者的區別應該很明了了:
HTTP
是超文本傳輸協議,信息是明文傳輸,HTTPS
則是在HTTP層下加了一層具有安全性的SSL/TLS加密傳輸協議,要用到CA證書。HTTP
是沒有身份認證的,客戶端無法知道對方的真實身份。HTTPS
加入了CA證書,可以確認對方信息。HTTP
默認端口為80,HTTPS
為443。HTTP
因為明文傳輸,容易被攻擊或者流量劫持。
怎么實現分塊傳輸,斷點續傳?
分塊傳輸
正常情況下,一次數據發完之后,服務器就會斷開鏈接。
所以一般要在請求頭中設置Connection
字段的值為:keep-alive
,表示維持連接不要斷開,一直到某個數據包的Connection
字段的值為close。
另外還有一種辦法可以維持TCP連接
,就是將請求數據進行分塊傳輸。
分塊傳輸指的是服務器發給客戶端的數據可以分成多個部分傳輸。
使用方法:
- 消息頭部設置
Transfer-Encoding: chunked
- 每一塊會表明長度
- 由一個標明長度為0的chunk標示結束
目的:
讓客戶端快速響應,減少等待時間。維持長連接。
但是、但是、這個分塊傳輸只在HTTP1.1
才有。HTTP2.0
支持了多路復用,單個連接可以承載任意數量的雙向數據流,也就是可以任意在一個連接在進行雙向傳輸,不需要分塊傳輸這個功能了。
斷點續傳
指的是客戶端想從文件上次中斷的地方開始下載或者上傳,這樣就算遇到網絡問題導致下載或上傳中斷也沒事了,保證好的用戶體驗。
使用方法:
- 客戶端請求報文頭部信息中加上
Range
字段,表示要從哪個字節開始下載,到哪個字節結束(Range: bytes=0-499) - 服務器端響應報文頭部信息中加上
Content-Range
,表示當前發送的數據的范圍,以及文件總大小(Content-Range: bytes 0-499/22400)。 ETag
字段表示文件的唯一性。
實際使用流程:
第一次
客戶端請求下載,服務器端會返回文件內容,和Etag標示,狀態碼為200。第二次
客戶端請求斷點續傳,會發送兩個頭部信息(Range:bytes=200-499,If-Range:Etag)。- 然后服務器會判斷
Etag
是否匹配,如果匹配則返回這一部分數據(Content-Range: bytes 200-499/22400),狀態碼為206,表示這是你請求的部分數據。否則會返回文件全部數據,狀態碼為200。
Http傳輸圖片有哪些方式
其實這種問題問的是對於Content-Type
的認識,一共三種方法:
- multipart/form-data
表單類型傳輸文件請求。通過設置content-type
為multipart/form-data
,來發送二進制格式文件。
支持多個文件上傳,還可以帶上文本參數。
這種是最常見的做法。
- image/png,image/jpeg
這種方法就是直接將圖片轉為二進制流
傳輸,服務器端也是直接讀取流中的數據轉成圖片即可。
但是這種方法有個缺點就是一次只能傳一張圖片。
- application/x-www-form-urlencoded,text/plain
還有個辦法就是將圖片轉成Base64
格式字符串,然后進行傳輸,和普通的文本參數一樣,設置application/x-www-form-urlencoded
或者text/plain
等Content-Type即可。
參考
https://wetest.qq.com/lab/view/110.html
https://www.zhihu.com/question/271701044
https://www.cnblogs.com/wqhwe/p/5407468.html
http://www.ruanyifeng.com/blog/2017/06/tcp-protocol.html
https://network.51cto.com/art/201909/602938.htm
https://www.dazhuanlan.com/2019/11/21/5dd5aeeff1d0b/
https://zhuanlan.zhihu.com/p/26559480
《網絡是怎樣連接的》
拜拜
感謝大家的閱讀,有一起學習的小伙伴可以關注下我的公眾號——碼上積木❤️❤️
每日一個知識點,積少成多,建立知識體系架構。
這里有一群很好的Android小伙伴,歡迎大家加入~