iOS老司機的網路相關Tips
持續創作,加速成長!這是我參與「掘金日新計劃 · 10 月更文挑戰」的第3天,點選檢視活動詳情
1. 前言: 作為一個有自我修養的iOS工程師, 對網路的理解體現在開發中的方方面面
- 如果你是個科班畢業的iOS開發者, 對計算機網路的基礎認識可能是通過<<計算機網路>>這本教材.
- 如果你是個其他專業轉向iOS的開發者, 對計算機網路的認識可能來自於這本無數大佬安利的<<圖解HTTP>>
- 下面就由我們來結合iOS開發日常工作中的方方面, 來一起對iOS中常用的網路相關知識做一個不成體系的梳理, 拋磚引玉, 如在閱讀過程中發現錯誤, 請及時在評論區交流指正:)
2. iOS開發中的網路相關基操Tips
2.1 HTTP的請求方式有哪些?
- GET、POST、PUT、DELETE、HEAD、OPTIONS
- 其實我們在開發過程中用的最多的請求方式的是GET和POST, 對其他的⽅式使⽤的很少, 在有些公司採⽤restful⻛格的時候會⽤PUT來做更新, DELETE做刪除.
2.1.1 GET和POST的區別
- 從用法來說, GET主要是用來獲取資源的, 語義上具有安全性、冪等性、可快取性;
- 從用法來說, POST主要是用來修改資源的, 語義上具有不安全性、非冪等性、不可快取性;
-
- 安全性, 指的是是否能引起server端的變化.
-
- 冪等性, 指的是單次請求和多次請求的結果是否一致.
-
- 可快取性, 指的是請求是否可以被快取.
2.2 關於HTTP的持久連線的理解
- 隨著我們要處理的資源越來越多, 如果還是採⽤非持久連線的⽅式就會很浪費資源, 因為會牽扯到⼤量的連線的建⽴和銷燬.
- 所以為了解決這種問題, 提出了持久連線來改進.
- 就是在連線建⽴以後, 處理完任務不是⽴即銷燬, ⽽是有⼀個等待時間, 在這段時間範圍內可以對同⼀服務的請求進⾏復⽤, 減少連線的建立和銷燬次數.
2.3 怎樣判斷一個HTTP請求是否已經完成了?
- 判斷⼀個請求是否完成的⽅式有兩種.
- 第⼀種: 通過響應報⽂中的
content-length
欄位來判斷接收的資料是否已經接收完畢了, 如果接收完 畢了就表示本次請求完成了. - 第⼆種: 在POST請求中會存在多次響應, 在最後⼀次響應的報⽂中會包含⼀個空的
chunck
, 我們可以以此來判斷請求是否完成了.
2.4 HTTP連線過程中的三次握手和四次揮手
2.4.1 三次握手
- 傳送⼀個http請求要先建⽴連線.
- ⾸先server端要監聽端⼝, 此時server端處於LISTEN狀態.
- client端傳送⼀個SYN同步包到server端, 並將⾃⼰(client端)的狀態置為SYN_SENT
- server端收到client的syn, 會回傳⼀個ACK確認資訊, 以及⼀個SYN同步包, 同意建⽴連線, 將server 端狀態置為SYN_RCVD.
- client端收到服務端的SYN包後, 傳送⼀個ACK給server端. 並將⾃⼰的狀態改為ESTABLISHED.
- server端接收到ACK資訊後, 會將狀態改為ESTABLISHED.
- 這樣就完成了三次握⼿, 就可以進⾏資料的傳遞了.
2.4.2 四次揮手
- 關於斷開連線的四次揮⼿的流程, 主要是因為全雙工通道的機制.
- client端傳送⼀個FIN訊號給server端, 並進⼊FIN_WAIT_1狀態.
- server端接收到訊息後會返回⼀個ACK確認, 並進⼊CLOSE_WAIT狀態.
- client端接收到ACK確認資訊後, 將狀態改為FIN_WAIT_2. 此時已經完成了半關閉狀態.
- 當server端要傳輸的資料也完成以後, 就會發送⼀個FIN訊號給client端, 並將狀態置為LAST_ACK.
- client端接收到FIN訊號後會返回⼀個ACK給server端, 並將狀態置為TIME_WAIT.
- server端在收到ACK確認資訊後, 會進⼊CLOSE狀態.
- client端會在等待2MSL(報⽂最⼤⽣存時間)的時間後進⼊CLOSE狀態.
2.4.3 為什麼要等待2MSL?
- 為了保證可靠關閉.
- 如果server沒有收到最後⼀個ACK, 那麼就會重發FIN.
- 為了避免端⼝重⽤帶來的資料混淆, 如果client直接進⼊CLOSE狀態, ⼜⽤相同的端⼝建⽴⼀個連線, 上⼀次連線的部分資料在⽹絡中延遲到達server, 資料就有可能發⽣混淆.
2.5 TCP和UDP的區別
- TCP是傳輸控制協議, 它的特點是: ⾯向連線的、可靠的、⾯向位元組流的, 流量控制、擁塞控制.
- UDP是⽤戶資料報協議, 它的特點是: ⽆連線、盡最⼤可能交付、⾯向報⽂的, 不保證資料的完整 性.
2.5.1 TCP是怎樣保證傳輸過程的可靠性的?
- TCP在保證傳輸的可靠性⽅⾯主要有以下機制
- 校驗和: 傳送⽅在傳送資料之前計算校驗和, 接收⽅收到資料後同樣計算, 如果不⼀致, 那麼傳輸有 誤.
- 確認應答: TCP進⾏傳輸時資料都進⾏編號, 每次接收⽅返回ACK都有確認序列號.
- 超時重傳: 如果傳送⽅傳送資料⼀段時間後沒有收到ACK, 那麼就重發資料.
- 對於超時重傳的情況有兩種
-
- ⼀種是客戶端傳送到服務端的資料超時了, 那麼服務端可能會收到兩份資料, 服務端會丟棄重複的資料.
-
- 還有⼀種是服務端確認資訊超時了, 那麼客戶端在收到確認資訊的時候什麼都不做.
2.5.2 TCP的流量控制與擁塞控制
- TCP的流量控制是通過滑動窗⼝協議來實現的. TCP協議報⽂頭包含16位的窗⼝⼤⼩, 接收⽅在返回ACK時會把⾃⼰的即時窗⼝填⼊, 傳送⽅就根據報⽂中窗⼝的⼤⼩來控制傳送的速度.
- 擁塞控制是為了解決⽹絡中湧⼊⼤量資料包的⼀種機制.
- 這⾥主要使⽤慢開始, 擁塞避免和快恢復, 快重傳兩種策略.
- - 慢開始是指剛開始傳送資料的時候, 擁塞窗⼝是1, 以後每次收到ACK後, 將擁塞窗⼝的值按照指數級增⻓, 當增⻓達到了擁塞窗⼝的⻔限值的時候, 就會以線性⽅式增⻓, 來控制傳送資料的速度.
- - 當傳送⽹絡擁塞的時候, 就會將擁塞窗⼝值改為1, 重新開始慢開始的流程. 同時將擁塞窗⼝的⻔限值改為擁塞時的⼀半.
- - 快恢復快重傳是基於慢開始的, 在發⽣⽹絡擁塞的時候, 是把擁塞窗⼝的⼤⼩調到擁塞值的⼀半, 然後以線性⽅式增⻓.
2.6 DNS域名解析相關
- DNS是做域名解析的, 我們在通過域名訪問伺服器的時候, ⾸先會通過DNS進⾏域名解析, 得到伺服器的IP地址, 然後再進⾏訪問.
- 域名解析使⽤的UDP的⽅式進⾏明⽂傳輸的. 採⽤udp是因為它的速度更快.
- 但是因為傳輸的明⽂, 所以容易遭到劫持.
- 所以在解決DNS劫持的時候主要有兩種⽅式, ⼀種是httpDNS, ⼀種是⻓連線.
- - httpDNS是指通過傳送⼀個http請求來解析域名. 因為普通的DNS劫持是基於UDP的, 所以我們通過 httpDNS是採⽤TCP的⽅式, 可以防⽌.
- - ⻓連線的⽅式是指我們建⽴⼀個⻓連線伺服器, 讓client與中間伺服器建⽴⻓連線, 並將⻓連線與域名解析伺服器通過內⽹專線的⽅式進⾏連線, 以此來避免DNS的劫持.
2.7 如何保證Cookie的安全
- 對cookie內容進⾏加密處理, 這種⽅式的缺點是不能避免指令碼攻擊.
- 在https下傳輸cookie, 這也是我們使⽤最多的⽅式.
- 設定cookie為httpOnly來防⽌跨站指令碼攻擊.
2.8 關於HTTPS
- HTTPS是在HTTP的基礎上增加了安全模組(TLS/SSL).
2.8.1 HTTPS的連線建立流程
1. ⾸先client端將當前⽀持的TLS版本號, 以及⽀持的加密演算法, 並⽣成⼀個隨機數C⼀起傳送給server端.
2. server端收到訊息後會選擇⼀套加密演算法, 並⽣成⼀個隨機數S, 連同server證書返回給client端
3. client端先校驗server證書, 然後根據預主祕鑰+C+S組裝會話祕鑰. 並通過server證書將預主祕鑰加密傳送給server端.
4. server端⽤私鑰進⾏解碼, 得到預主祕鑰後, 組裝會話祕鑰, 然後加密握⼿訊息.
2.9 ISO模型的七層架構(應表會傳網數物)
- 七層架構分別是: 應⽤層、表示層、會話層、傳輸層、⽹絡層、資料鏈路層、物理層.
- 應⽤層: 最⾼層, 直接⾯對⽤戶.
- 表示層: ⽤來將資料轉換成另外⼀種格式, ⽐如⽂字、影片、圖⽚等.
- 會話層: 負責建⽴和斷開連線.
- 傳輸層: TCP、UDP都屬於這⼀層的協議.
- ⽹絡層: 定義了IP和⼦⽹掩碼, ⽤來確定⽹段, 通過路由器和交換機進⾏傳輸. IP協議就是屬於⽹絡層的協議.
- 資料鏈路層: 把⽐特流封裝成資料幀的格式.
- 物理層: 通過⽹線, 光纜等這種物理⽅式將電腦連線起來, 傳遞的是⽐特流.
2.10 什麼是BIO/NIO/AIO?
- BIO: 同步阻塞IO, 每⼀個客戶端連線, 服務端都會對應⼀個處理執行緒, 對於沒有分配到處理執行緒的連 接就會被阻塞或者拒絕. 相當於⼀個連線⼀個執行緒.
- NIO: 同步⾮阻塞IO, 基於Reactor模型, 客戶端和channel進⾏通訊, channel可以進⾏讀寫操作. 通過多路復⽤器seletor來輪詢註冊在其上的channel, ⽽後再進⾏IO操作. 這樣的話, 在進⾏IO操作的時候再⽤⼀個執行緒去處理就好. 也就是⼀個請求⼀個執行緒.
- AIO: 非同步⾮阻塞IO, 相⽐NIO更進⼀步, 完全有作業系統來完成請求的處理, 然後通知服務端開啟線 程進⾏處理, 因此是⼀個有效請求⼀個執行緒.
2.11 淺談一下對HTTP的理解
- ⾸先http是超⽂本傳輸協議, 它是基於TCP協議的應⽤層傳輸協議.
- 它的特點主要有兩個, ⽆連線和⽆狀態
- - 關於⽆連線是指限制每次連線只處理⼀個請求. 伺服器處理完客戶端的請求, 並收到客戶端的應答後 就斷開連線. 這是早期採⽤的⽅式, 為了追求快, 傳輸的資源少. 但是隨著我們要處理的資源增多, 就提出了持久連線的⽅式, 來複⽤連線, 通過設定⼀個時間, 在這段時間內都可以復⽤此次連線, 只有在超過這個時間後才會斷開連線.
- - 關於⽆狀態是指每次請求不會記錄狀態, 為了解決這種⽆狀態的問題, 提出了cookie和session機制. cookie和session都是⽤來記錄⽤戶狀態, 區分⽤戶的. 主要的區別在於cookie是儲存在客戶端, session是儲存在服務端的. session的實現也是基於cookie機制的.
- 另外我們在傳送⼀個http請求的時候還主要請求報⽂和響應報⽂.
- - 關於請求報⽂主要包含請求⾏, 在請求⾏⾥包含了請求⽅式是GET還是POST, 還有URL, 以及當前協議的版本是http1.0還是1.1.
- - 除了請求⾏還有請求的頭部欄位, 這⾥是以key-value的形式存在, 包含多個鍵值對
- - 還有就是實體主體, 在get請求時沒有這⼀塊, 在POST請求時有.
- - 關於響應報⽂也包含響應⾏、頭部欄位、以及實體主體. 在響應報⽂的響應⾏中存在著當前的版本、狀態碼、短語, 也就是描述資訊.
2.12 常見的狀態碼
- 1xx: 目前是協議的中間狀態, 還需要後續請求
-
- 100: 請求者應當繼續傳送請求, 服務端返回100表示已收到請求的第一部分, 正在等待剩餘部分.
-
- 101: 切換請求協議, 客戶端已要求服務端切換協議, 服務端已確認並準備切換. 如從HTTP切換到WebSocket
- 2xx: 表示請求成功
-
- 200: 請求成功, 有響應體, 伺服器成功返回資料
-
- 204: 服務端成功處理了請求, 但沒有返回任何內容(無內容)
-
- 205: 服務端成功處理了請求, 但沒有返回任何內容(重置內容)
- 3xx: 表示重定向狀態, 需要重新請求
-
- 301: 永久重定向, 會快取
-
- 302: 臨時重定向, 不會快取
-
- 304: 協商快取命中
- 4xx: 表示客戶端請求報文錯誤
-
- 400: 請求錯誤, 服務端不理解請求的語法
-
- 403: 伺服器禁止訪問, 拒絕請求
-
- 404: 資源未找到, 請求的網頁不存在
- 5xx: 表示服務端錯誤
-
- 500: 伺服器端錯誤, 無法完成請求
-
- 503: 伺服器繁忙(服務不可用, 由於超載或停機維護, 通常只是暫時狀態)
-
- 504: 服務端作為閘道器或代理, 但是沒有及時從上游伺服器收到請求.(閘道器超時)
發文不易, 喜歡點讚的人更有好運氣👍 :), 定期更新+關注不迷路~
ps:歡迎加入筆者18年建立的研究iOS稽核及前沿技術的三千人扣群:662339934,坑位有限,備註“掘金網友”可被群管通過~
- iOS老司機可落地在中大型iOS專案中的5大接地氣設計模式合集
- iOS老司機的跨端跨平臺Hybrid開發Tips
- iOS老司機的2022年回顧, 聊聊寒冬下的實用<<談判力>>
- iOS老司機可落地的中大型iOS專案中的設計模式優化Tips_橋接模式
- iOS老司機的多執行緒PThread學習分享
- iOS老司機整理, iOSer必會的經典演算法_2
- iOS老司機的<<藍海轉型>>讀書分享
- iOS老司機的<<程式設計師的自我修養:連結、裝載與庫>>讀書分享
- iOS老司機的接地氣演算法Tips
- iOS老司機的RunLoop原理探究及實用Tips
- iOS老司機整理, iOSer必會的經典演算法_1
- iOS老司機的App啟動優化Tips, 讓啟動速度提升10%
- iOS老司機的網路相關Tips
- 戀上資料結構與演算法
- iOS老司機帶你一起把App的崩潰率降到0.1%以下
- 探究Swift的String底層實現
- iOS老司機萬字整理, 可能是最全的Swift Tips
- iOS老司機可落地的中大型iOS專案中的設計模式優化Tips
- 聊一聊Swift中的閉包
- 位元組同學推薦_編寫高質量Objective-C程式碼的52個有效方法