計算機網絡是計算機科學與技術專業的必修課,也是移動端,前端,後端都會涉及並用到的知識點,可想而知它的重要性。所以它也成爲了iOS面試中經常被問及的問題。準備面試的話,網絡相關的知識點一定不能錯過。這裏總結了一些我認爲有用的和最近面試遇到的網絡相關知識點。
去年寫過一篇《圖解TCP/IP》總結的文章,也可以對着看下。
計算機網絡是如何分層的
網絡有兩種分層模型,一種是ISO(國際標準化組織)制定的OSI(Open System Interconnect)模型,它將網絡分爲七層。一種是TCP/IP的四層網絡模型。OSI是一種學術上的國際標準,理想概念,TCP/IP是事實上的國際標準,被廣泛應用於現實生活中。兩者的關係可以看這個圖:
注:也有說五層模型的,它跟四層模型的區別就是,在OSI模型中的數據鏈路層和物理層,前者將其作爲兩層,後者將其合併爲一層稱爲網絡接口層。一般作爲面試題的話都是需要講出OSI七層模型的。
各個分層的含義以及它們之間的關係用這張圖表示:
Http協議
http協議特性
- HTTP 協議構建於 TCP/IP 協議之上,是一個應用層協議,默認端口號是 80
- 靈活:HTTP允許傳輸任意類型的數據對象。正在傳輸的類型由Content-Type加以標記。
- 無狀態:無連接的含義是限制每次連接只處理一個請求。服務器處理完客戶的請求,並收到客戶的應答後,即斷開連接。
- 無狀態:HTTP協議是無狀態協議。無狀態是指協議對於事務處理沒有記憶能力。缺少狀態意味着如果後續處理需要前面的信息,則它必須重傳。
請求方法
-
GET:請求獲取Request-URI標識的資源,請求參數附加在url上,明文展示。
-
POST:在Request-URI所標識的資源後附加新的數據,常用於修改服務器資源或者提交資源到服務器。POST請求體是放到body中的,可以指定編碼方式,更加安全。
-
HEAD:請求獲取由Request-URI所標識的資源的響應消息報頭。
-
PUT:請求服務器存儲一個資源,並用Request-URI作爲其標識。
-
DELETE:請求服務器刪除Request-URI所標識的資源。
-
TRACE:請求服務器回送收到的請求信息,主要用於測試或診斷。
-
OPTIONS:請求查詢服務器的性能,或者查詢與資源相關的選項和需求。
請求和響應報文
以該鏈接爲例:zhangferry.com/2019/08/31/…
在Chrome查看其請求的Headers信息。
General
這裏標記了請求的URL,請求方法爲GET。狀態碼爲304,代表文件未修改,可以直接使用緩存的文件。遠程地址爲185.199.111.153:443,此IP爲Github 服務器地址,是因爲我的博客是部署在GitHub上的。
除了304還有別的狀態碼,分別是:
200 OK
客戶端請求成功301 Moved Permanently
請求永久重定向302 Moved Temporarily
請求臨時重定向304 Not Modified
文件未修改,可以直接使用緩存的文件。400 Bad Request
由於客戶端請求有語法錯誤,不能被服務器所理解。401 Unauthorized
請求未經授權。這個狀態代碼必須和WWW-Authenticate報頭域一起使用403 Forbidden
服務器收到請求,但是拒絕提供服務。服務器通常會在響應正文中給出不提供服務的原因404 Not Found
請求的資源不存在,例如,輸入了錯誤的URL500 Internal Server Error
服務器發生不可預期的錯誤,導致無法完成客戶端的請求。503 Service Unavailable
服務器當前不能夠處理客戶端的請求,在一段時間之後,服務器可能會恢復正常。
Response Headers:
content-encoding:用於指定壓縮算法
content-length:資源的大小,以十進制字節數表示。
content-type:指示資源的媒體類型。圖中所示內容類型爲html的文本類型,文字編碼方式爲utf-8
last-modified:上次內容修改的日期,爲6月8號
status:304 文件未修改狀態碼
注:其中content-type在響應頭中代表,需要解析的格式。在請求頭中代表上傳到服務器的內容格式。
Request Headers:
:method:GET請求
:path:url路徑
:scheme:https請求
accept:通知服務器可以返回的數據類型。
accept-encoding:編碼算法,通常是壓縮算法,可用於發送回的資源
accept-language:通知服務器預期發送回的語言類型。這是一個提示,並不一定由用戶完全控制:服務器應該始終注意不要覆蓋用戶的顯式選擇(比如從下拉列表中選擇語言)。
cookie:瀏覽器cookie
user-agent:用戶代理,標記系統和瀏覽器內核
更多請求頭的字段含義可以參考這裏:HTTP headers
TCP三次握手和四次揮手的過程以及爲什麼要有三次和四次
在瞭解TCP握手之前我們先看下TCP的報文樣式:
其中控制位(Control Flag)標記着握手階段的各個狀態。
TCP三次握手
示意圖如下:
三次握手是指建立一個TCP連接時,需要客戶端和服務器總共發送3個數據包。
1、第一次握手(SYN=1, seq=x)
客戶端發送一個 TCP 的 SYN 標誌位置1的包,指明客戶端打算連接的服務器的端口,以及初始序號 X,保存在包頭的序列號(Sequence Number)字段裏。
發送完畢後,客戶端進入 SYN_SEND
狀態。
2、第二次握手(SYN=1, ACK=1, seq=y, ACKnum=x+1)
服務器發回確認包(ACK)應答。即 SYN 標誌位和 ACK 標誌位均爲1。服務器端選擇自己 ISN 序列號,放到 Seq 域裏,同時將確認序號(Acknowledgement Number)設置爲客戶的 ISN 加1,即X+1。 發送完畢後,服務器端進入 SYN_RCVD
狀態。
3、第三次握手(ACK=1, ACKnum=y+1)
客戶端再次發送確認包(ACK),SYN 標誌位爲0,ACK 標誌位爲1,並且把服務器發來 ACK 的序號字段+1,放在確定字段中發送給對方,並且在數據段放寫ISN的+1
發送完畢後,客戶端進入 ESTABLISHED
狀態,當服務器端接收到這個包時,也進入 ESTABLISHED
狀態,TCP 握手結束。
問題一:爲什麼需要三次握手呢?
在謝希仁著的《計算機網絡》裏說,『爲了防止已失效的連接請求報文段突然又傳送到了服務端,因而產生錯誤』。怎麼理解呢,我們假設一種情況,有一個建立連接的第一次握手的報文段因爲滯留到網絡中過了較長時間才發送到服務端。這時服務器是要做ACK應答的,如果只有兩次握手就代表連接建立,那服務器此時就要等待客戶端發送建立連接之後的數據。而這只是一個因滯留而廢棄的請求,是不是白白浪費了很多服務器資源。
從另一個角度看這個問題,TCP是全雙工的通信模式,需要保證兩端都已經建立可靠有效的連接。在三次握手過程中,我們可以確認的狀態是:
第一次握手:服務器確認自己接收OK,服務端確認客戶端發送OK。
第二次握手:客戶端確認自己發送OK,客戶端確認自己接收OK,客戶端確認服務器發送OK,客戶端確認服務器接收OK。
第三次握手:服務器確認自己發送OK,服務器確認客戶端接收OK。
只有握手三次才能達到全雙工的目的:確認自己和對方都能夠接收和發送消息。
TCP四次揮手
示意圖如下:
四次揮手錶示要發送四個包,揮手的目的是斷開連接。
1、第一次揮手(FIN=1, seq=x)
假設客戶端想要關閉連接,客戶端發送一個 FIN 標誌位置爲1的包,表示自己已經沒有數據可以發送了,但是仍然可以接受數據。
發送完畢後,客戶端進入 FIN_WAIT_1
狀態。
2、第二次揮手(ACK=1,ACKnum=x+1)
服務器端確認客戶端的 FIN 包,發送一個確認包,表明自己接受到了客戶端關閉連接的請求,但還沒有準備好關閉連接。
發送完畢後,服務器端進入 CLOSE_WAIT
狀態,客戶端接收到這個確認包之後,進入 FIN_WAIT_2
狀態,等待服務器端關閉連接。
3、第三次揮手(FIN=1,seq=y)
服務器端準備好關閉連接時,向客戶端發送結束連接請求,FIN 置爲1。
發送完畢後,服務器端進入 LAST_ACK
狀態,等待來自客戶端的最後一個ACK。
4、第四次揮手(ACK=1,ACKnum=y+1)
客戶端接收到來自服務器端的關閉請求,發送一個確認包,並進入 TIME_WAIT
狀態,等待可能出現的要求重傳的 ACK 包。
服務器端接收到這個確認包之後,關閉連接,進入 CLOSED
狀態。
客戶端等待了某個固定時間(兩個最大段生命週期,2MSL,2 Maximum Segment Lifetime)之後,沒有收到服務器端的 ACK ,認爲服務器端已經正常關閉連接,於是自己也關閉連接,進入 CLOSED
狀態。
問題一:爲什麼揮手需要四次呢?爲什麼不能將ACK和FIN報文一起發送?
當服務器收到FIN報文時,很可能並不會立即關閉SOCKET,所以只能先回復一個ACK報文,告訴客戶端『你發的FIN我收到了』。只有等到服務端所有的報文都發送完了,才能發FIN報文,所以要將ACK和FIN分開發送,這就導致需要四次揮手。
問題二:爲什麼TIMED_WAIT之後要等2MSL才進入CLOSED狀態?
MSL是TCP報文的最大生命週期,因爲TIME_WAIT持續在2MSL就可以保證在兩個傳輸方向上的尚未接收到或者遲到的報文段已經消失,同時也是在理論上保證最後一個報文可靠到達。假設最後一個ACK丟失,那麼服務器會再重發一個FIN,這是雖然客戶端的進程不在了,但是TCP連接還在,仍然可以重發LAST_ACK。
HTTPS的流程
HTTPS = HTTP + TLS/SSL,它使用的端口默認爲443,它的建立可以用下圖表示:
1、客戶端首次請求服務器,告訴服務器自己支持的協議版本,支持的加密算法及壓縮算法,並生成一個隨機數(client random)告知服務器。
2、服務器確認雙方使用的加密方法,並返回給客戶端證書以及一個服務器生成的隨機數(server random)
3、客戶端收到證書後,首先驗證證書的有效性,然後生成一個新的隨機數(premaster secret),並使用數字證書中的公鑰,加密這個隨機數,發送給服務器。
4、服務器接收到加密後的隨機數後,使用私鑰進行解密,獲取這個隨機數(premaster secret
5、服務器和客戶端根據約定的加密方法,使用前面的三個隨機數(client random, server random, premaster secret),生成『對話密鑰』(session key),用來加密接下來的整個對話過程(對稱加密)。
有一篇由淺入深介紹HTTPS的文章可以閱讀一下:看圖學HTTPS
問題一:爲什麼握手過程需要三個隨機數,而且安全性只取決於第三個隨機數?
前兩個隨機數是明文傳輸,存在被攔截的風險,第三個隨機數是通過證書公鑰加密的,只有它是經過加密的,所以它保證了整個流程的安全性。前兩個隨機數的目的是爲了保證最終對話密鑰的『更加隨機性』。
問題二:Charles如何實現HTTPS的攔截?
Charles要實現對https的攔截,需要在客戶端安裝Charles的證書並信任它,然後Charles扮演中間人,在客戶端面前充當服務器,在服務器面前充當客戶端。
問題三:爲什麼有些HTTPS請求(例如微信)抓包結果仍是加密的,如何實現的?
我在聊天過程中並沒有抓到會話的請求,在小程序啓動的時候到是抓到了一個加密內容。我手動觸發該鏈接會下載一個加密文件,我猜測這種加密是內容層面的加密,它的解密是由客戶端完成的,而不是在HTTPS建立過程完成的。
另外在研究這個問題的過程中,又發現了一些有趣的問題:
1、圖中所示的三個https請求分別對應三個不同類型的圖標,它們分別代表什麼意思呢?
2、第三個請求https://mtalk.google.com:5228
圖標和請求內容都加了鎖,這個加鎖是在https之上又加了一層鎖嗎?
這些問題暫時沒有確切的答案,希望瞭解的小夥伴告知一下哈。
DNS解析流程
DNS(Domain name system)域名系統。DNS是因特網上作爲域名和IP地址相互映射的一個分佈式數據庫,能夠使用戶通過域名訪問到對應的服務器(IP地址)。具體的解析流程是這樣的:
1、瀏覽器中輸入想要訪問的網站域名,操作系統會檢查本地hosts文件是否有這個網址的映射關係,如果有就調用這個IP地址映射,完成域名解析。沒有的話就走第二步。
2、客戶端迴向本地DNS服務器發起查詢,如果本地DNS服務器收到請求,並可以在本地配置區域資源中查到該域名,就將對應結果返回爲給客戶端。如果沒有就走第三步。
3、根據本地DNS服務器的設置,採用遞歸或者迭代查詢,直至解析完成。
其中遞歸查詢和迭代查詢可以用如下兩圖表示。
遞歸查詢
如圖所示,遞歸查詢是由DNS服務器一級一級查詢傳遞的。
迭代查詢
如果所示,迭代查詢是找到指定DNS服務器,由客戶端發起查詢。
DNS劫持
DNS劫持發生在DNS服務器上,當客戶端請求解析域名時將其導向錯誤的服務器(IP)地址。
常見的解決辦法是使用自己的解析服務器或者是將域名以IP地址的方式發出去以繞過DNS解析。
Cookie和Session的區別
HTTP 是無狀態協議,說明它不能以狀態來區分和管理請求和響應。也就是說,服務器單從網絡連接上無從知道客戶身份。
可是怎麼辦呢?就給客戶端們頒發一個通行證吧,每人一個,無論誰訪問都必須攜帶自己通行證。這樣服務器就能從通行證上確認客戶身份了。這就是Cookie的工作原理。
-
Cookie:Cookie是客戶端保存用戶信息的一種機制,用來記錄用戶的一些信息,實際上Cookie是服務器在本地機器上存儲的一小段文本,並隨着每次請求發送到服務器。Cookie技術通過請求和響應報文中寫入Cookie信息來控制客戶端的狀態。
-
Session:Session機制是一種服務器端的機制,服務器使用一種類似於散列表的結構來保存信息。當有用戶請求創建一個session時,服務器會先檢查這個客戶端裏是否已經包含了一個Session標識(session id),如果有就通過session id把session檢索出來。如果沒有就創建一個對應此Session的session id。這個session id會在本次響應中返回給客戶端。
兩者有以下區別:
1、存儲位置:Cookie存放在客戶端上,Session數據存放在服務器上。
2、Session 的運行依賴 session id,而 session id 是存在 Cookie 中的,也就是說,如果瀏覽器禁用了 Cookie ,同時 Session 也會失效
3、安全性:Cookie存在瀏覽器中,可能會被一些程序複製,篡改;而Session存在服務器相對安全很多。
4、性能:Session會在一定時間內保存在服務器上,當訪問增多,會對服務器造成一定的壓力。考慮到減輕服務器壓力,應當使用Cookie
CDN是幹什麼用的
CDN(Content Delivery Network),根本作用是將網站的內容發佈到最接近用戶的網絡『邊緣』,以提高用戶訪問速度。概括的來說:CDN = 鏡像(Mirror) + 緩存(Cache) + 整體負載均衡(GSLB)。
目前CDN都以緩存網站中的靜態數據爲主,如CSS、JS、圖片和靜態網頁等數據。用戶在從主站服務器請求到動態內容後再從CDN上下載這些靜態數據,從而加速網頁數據內容的下載速度,如淘寶有90%以上的數據都是由CDN來提供的。
CDN工作流程
一個用戶訪問某個靜態文件(如CSS),這個靜態文件的域名假如是www.baidu.com,而這個域名最終會被指向CDN全局中CDN負載均衡服務器,再由這個負載均衡服務器來最終分配是哪個地方的訪問用戶,返回給離這個訪問用戶最近的CDN節點。之後用戶就直接去這個CDN節點訪問這個靜態文件了,如果這個節點中請求的文件不存在,就會再回到源站去獲取這個文件,然後再返回給用戶。
Socket的作用
socket位於應用層和傳輸層之間:
它的作用是爲了應用層能夠更方便的將數據經由傳輸層來傳輸。所以它的本質就是對TCP/IP的封裝,然後應用程序直接調用socket API即可進行通信。上文中說的三次握手和四次揮手即是通過socket完成的。
我們可以從iOS中網絡庫分層找到BSD Sockets
,它是位於CFNetwork
之下。在CFNetwork
中還有一個CFSocket
,推測是對BSD Sockets
的封裝。
WebRTC是幹什麼用的
WebRTC是一個可以用在視頻聊天,音頻聊天或P2P文件分享等Web App中的 API。藉助WebRTC,你可以在基於開放標準的應用程序中添加實時通信功能。它支持在同級之間發送視頻,語音和通用數據,從而使開發人員能夠構建功能強大的語音和視頻通信解決方案。該技術可在所有現代瀏覽器以及所有主要平臺的本機客戶端上使用。WebRTC項目是開源的,並得到Apple,Google,Microsoft和Mozilla等的支持。
如果某一請求只在某一地特定時刻失敗率較高,會有哪些原因
這個是某公司二面時的問題,是一個開放性問題,我總結了以下幾點可能:
1、該時刻請求量過大
2、該地的網絡節點較不穩定
3、用戶行爲習慣,比如該時刻爲上班高峯期,或者某個羣體的特定習慣
如果有對網絡方面比較熟悉的小夥伴也可以補充。