iOS老司機的網絡相關Tips

語言: CN / TW / HK

持續創作,加速成長!這是我參與「掘金日新計劃 · 10 月更文挑戰」的第3天,點擊查看活動詳情

1. 前言: 作為一個有自我修養的iOS工程師, 對網絡的理解體現在開發中的方方面面

  • 如果你是個科班畢業的iOS開發者, 對計算機網絡的基礎認識可能是通過<<計算機網絡>>這本教材. image.png
  • 如果你是個其他專業轉向iOS的開發者, 對計算機網絡的認識可能來自於這本無數大佬安利的<<圖解HTTP>> image.png
  • 下面就由我們來結合iOS開發日常工作中的方方面, 來一起對iOS中常用的網絡相關知識做一個不成體系的梳理, 拋磚引玉, 如在閲讀過程中發現錯誤, 請及時在評論區交流指正:)

2. iOS開發中的網絡相關基操Tips

2.1 HTTP的請求方式有哪些?

image.png - 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的流量控制與擁塞控制

image.png - TCP的流量控制是通過滑動窗⼝協議來實現的. TCP協議報⽂頭包含16位的窗⼝⼤⼩, 接收⽅在返回ACK時會把⾃⼰的即時窗⼝填⼊, 發送⽅就根據報⽂中窗⼝的⼤⼩來控制發送的速度. - 擁塞控制是為了解決⽹絡中湧⼊⼤量數據包的⼀種機制. - 這⾥主要使⽤慢開始, 擁塞避免和快恢復, 快重傳兩種策略.
- - 慢開始是指剛開始發送數據的時候, 擁塞窗⼝是1, 以後每次收到ACK後, 將擁塞窗⼝的值按照指數級增⻓, 當增⻓達到了擁塞窗⼝的⻔限值的時候, 就會以線性⽅式增⻓, 來控制發送數據的速度. - - 當發送⽹絡擁塞的時候, 就會將擁塞窗⼝值改為1, 重新開始慢開始的流程. 同時將擁塞窗⼝的⻔限值改為擁塞時的⼀半. - - 快恢復快重傳是基於慢開始的, 在發⽣⽹絡擁塞的時候, 是把擁塞窗⼝的⼤⼩調到擁塞值的⼀半, 然後以線性⽅式增⻓.

2.6 DNS域名解析相關

image.png - DNS是做域名解析的, 我們在通過域名訪問服務器的時候, ⾸先會通過DNS進⾏域名解析, 得到服務器的IP地址, 然後再進⾏訪問. - 域名解析使⽤的UDP的⽅式進⾏明⽂傳輸的. 採⽤udp是因為它的速度更快. - 但是因為傳輸的明⽂, 所以容易遭到劫持. - 所以在解決DNS劫持的時候主要有兩種⽅式, ⼀種是httpDNS, ⼀種是⻓連接. - - httpDNS是指通過發送⼀個http請求來解析域名. 因為普通的DNS劫持是基於UDP的, 所以我們通過 httpDNS是採⽤TCP的⽅式, 可以防⽌. - - ⻓連接的⽅式是指我們建⽴⼀個⻓連接服務器, 讓client與中間服務器建⽴⻓連接, 並將⻓連接與域名解析服務器通過內⽹專線的⽅式進⾏連接, 以此來避免DNS的劫持.

2.7 如何保證Cookie的安全

image.png - 對cookie內容進⾏加密處理, 這種⽅式的缺點是不能避免腳本攻擊. - 在https下傳輸cookie, 這也是我們使⽤最多的⽅式. - 設置cookie為httpOnly來防⽌跨站腳本攻擊.

2.8 關於HTTPS

  • HTTPS是在HTTP的基礎上增加了安全模塊(TLS/SSL).

2.8.1 HTTPS的連接建立流程

image.png 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, 每⼀個客户端連接, 服務端都會對應⼀個處理線程, 對於沒有分配到處理線程的連 接就會被阻塞或者拒絕. 相當於⼀個連接⼀個線程.

image.png

  • NIO: 同步⾮阻塞IO, 基於Reactor模型, 客户端和channel進⾏通信, channel可以進⾏讀寫操作. 通過多路復⽤器seletor來輪詢註冊在其上的channel, ⽽後再進⾏IO操作. 這樣的話, 在進⾏IO操作的時候再⽤⼀個線程去處理就好. 也就是⼀個請求⼀個線程.

image.png

  • AIO: 異步⾮阻塞IO, 相⽐NIO更進⼀步, 完全有操作系統來完成請求的處理, 然後通知服務端開啟線 程進⾏處理, 因此是⼀個有效請求⼀個線程.

2.11 淺談一下對HTTP的理解

image.png - ⾸先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,坑位有限,備註“掘金網友”可被羣管通過~