網絡一直是項目里比較重要的一個模塊,Android開源項目上出現過很多優秀的網絡框架。從一開始只是一些對HttpClient和HttpUrlConnection簡易封裝使用的工具類,到后來Google開源的比較完善豐富的Volley,再到如今比較流行的Okhttp、Retrofit。他們之間存在異同,這個系列主要想通過對網絡基礎知識、Android網絡框架的解析來理清他們的關系以及原理。
一.計算機網絡體系結構
每個程序員的基本知識,OSI的七層模型:
其中表示層和會話層沒有協議,所以我們重點解釋一下其他5層作用
1.應用層:如http協議,它實際上是定義了如何包裝和解析數據,應用層是http協議的話,則會按照協議規定包裝數據,如按照請求行、請求頭、請求體包裝,包裝好數據后將數據傳至運輸層。
2.傳輸層:運輸層有TCP和UDP兩種協議,分別對應可靠的運輸和不可靠的運輸,如TCP因為要提供可靠的傳輸,所以內部要解決如何建立連接、如何保證傳輸是可靠的不丟數據、如何調節流量控制和擁塞控制。關于這一層,我們平常一般都是和Socket打交道,Socket是一組封裝的編程調用接口,通過它,我們就能操作TCP、UDP進行連接的建立等。我們平常使用Socket進行連接建立的時候,一般都要指定端口號,所以這一層指定了把數據送到對應的端口號。
3.網絡層:這一層IP協議,以及一些路由選擇協議等等,所以這一層的指定了數據要傳輸到哪個IP地址。中間涉及到一些最優線路,路由選擇算法等等。
4.數據鏈路層:印象比較深的就是ARP協議,負責把IP地址解析為MAC地址,即硬件地址,這樣就找到了對應的唯一的機器。
5.物理層:這一層就是最底層了,提供二進制流傳輸服務,也就是也就是真正開始通過傳輸介質(有線、無線)開始進行數據的傳輸了。
所以通過上面五層的各司其職,實現物理傳輸介質--MAC地址--IP地址--端口號--獲取到數據根據應用層協議解析數據最終實現了網絡通信和數據傳輸。
TCP和UDP使用IP協議從一個網絡傳送數據包到另一個網絡。把IP想像成一種高速公路,它允許其它協議在上面行駛并找到到其它電腦的出口。TCP和UDP是高速公路上的“卡車”,它們攜帶的貨物就是像HTTP,文件傳輸協議FTP這樣的協議等。
二.HTTP相關
1.HTTP是無連接無狀態的。
無連接:并不是說不需要連接,Http協議只是一個應用層協議,最終還是要靠運輸層的如TCP協議向上提供的服務進行連接。無連接的含義是http約定了每次連接只處理一個請求,一次請求完成后就斷開連接,這樣主要是為了緩解服務器的壓力,減小連接對服務器資源的占用。我的理解是,建立連接實際上是運輸層的事,面向應用層的http來說的話,它就是無連接的,因為上層對下層無感知。
無狀態:每個請求之間都是獨立的,對于之前的請求事務沒有記憶的能力。所以就出現了像
Cookie這種,用來保存一些狀態的東西。
2.請求報文與響應報文
- 關于Get和Post的區別:
1.Get會把請求參數都拼接在url后面,最終顯示在地址欄,而Post則會把請求參數數據放進請求體中,不會再地址欄顯示出來
2.傳遞參數的長度限制,Get請求URL 的最大長度是 2048 個字符,Post無限制。
2.HTTP的緩存機制
Http的緩存主要利用header里的兩個字段來控制:
① Cache-control主要包含以及幾個字段:
- private:則只有客戶端可以緩存
- public:客戶端和代理服務器都可以緩存
- max-age:緩存的過期時間
- no-cache:代表不緩沖過期的資源,緩存會向源服務器進行有效確認
- no-store:所有內存都不會進行緩存
②ETag:即用來進行對比緩存,Etag是服務端資源的一個標識碼
當客戶端發送第一次請求時服務端會下發當前請求資源的標識碼Etag,下次再請求時,客戶端則會通過header里的If-None-Match將這個標識碼Etag帶上,服務端將客戶端傳來的Etag與最新的資源Etag做對比,如果一樣,則表示資源沒有更新,返回304。
通過Cache-control和Etag的配合來實現Http的緩存機制。
4.,Http2.0相對于Http1.x的對比:
khttp支持配置使用Http 2.0協議,Http2.0相對于Http1.x來說提升是巨大的,主要有以下幾點:
二進制格式:http1.x是文本協議,而http2.0是二進制以幀為基本單位,是一個二進制協議,一幀中除了包含數據外同時還包含該幀的標識:Stream Identifier,即標識了該幀屬于哪個request,使得網絡傳輸變得十分靈活。
多路復用:一個很大的改進,原先http1.x一個連接一個請求的情況有比較大的局限性,也引發了很多問題,如建立多個連接的消耗以及效率問題。
http1.x為了解決效率問題,可能會盡量多的發起并發的請求去加載資源,然而瀏覽器對于同一域名下的并發請求有限制,而優化的手段一般是將請求的資源放到不同的域名下來突破這種限制。
而http2.0支持的多路復用可以很好的解決這個問題,多個請求共用一個TCP連接,多個請求可以同時在這個TCP連接上并發,一個是解決了建立多個TCP連接的消耗問題,一個也解決了效率的問題。那么是什么原理支撐多個請求可以在一個TCP連接上并發呢?基本原理就是上面的二進制分幀,因為每一幀都有一個身份標識,所以多個請求的不同幀可以并發的無序發送出去,在服務端會根據每一幀的身份標識,將其整理到對應的request中。
header頭部壓縮:主要是通過壓縮header來減少請求的大小,減少流量消耗,提高效率。因為之前存在一個問題是,每次請求都要帶上header,而這個header中的數據通常是一層不變的。
支持服務端推送
4.HTTP的缺點
- 通信使用明文(不加密),內容可能被竊聽(抓包工具可以獲取請求和響應內容)
- 不驗證通訊方的身分,任何人都坑你發送請求,不管對方是誰都返回相應
- 無法證明報文的完整性,可能會遭到篡改,即沒有辦法確認發出的請求/相應前后一致。
三.HTTPS
http是超文本傳輸協議,而https可以簡單理解為安全的http協議。https通過在http協議下添加了一層ssl協議對數據進行加密從而保證了安全。https的作用主要有兩點:
- 建立安全的信息傳輸通道,保證數據傳輸安全;
- 確認網站的真實性。
而非對稱加密算法之所以能實現安全傳輸的核心精華就是:
公鑰加密的信息只能用私鑰解開,私鑰加密的信息只能被公鑰解開
對稱加密(也叫私鑰加密):加密和解密用的都是相同的秘鑰,優點是速度快,缺點是安全性低。
常見的對稱加密算法有DES、AES、RC4、IDEA。
非對稱加密:非對稱加密有一個秘鑰對,分為公鑰和私鑰。一般來說,私鑰自己持有,公鑰可以公開給對方,優點是安全性比對稱加密高,缺點是數據傳輸效率比對稱加密低。采用公鑰加密的信息只有對應的私鑰可以解密。常見的非對稱加密包括RSA、DSA/DSS等。
對于Https是對稱加密和非對稱加密結合使用,使用非對稱加密完成秘鑰的傳遞,然后使用對稱秘鑰進行數據加密和解密。二者結合既保證了安全性,又提高了數據傳輸效率。
1.HTTP與HTTPS的相同和異同點
①、HTTP與HTTPS的相同點:
大多數情況下,HTTP和HTTPS是相同的,因此都采用同一個基礎協議,作為HTTP或者HTTPS客戶端--瀏覽器/app等,設置一個連接到web服務器指定的寬口。當服務器接收到請求,它會返回一個狀態碼以及消息,這個回應可能是請求信息、或者指示某個錯誤發送的錯誤信息。系統使用統一資源定位符URI,因此資源可以被唯一指定。在表面上HTTPS和HTTP唯一不同的只是一個協議頭HTTPS的說明,其他都一樣。
②、HTTP與HTTPS的不同點:
- HTTPS需要用到CA申請證書。
- HTTP是超文本傳輸協議,信息是明文的;HTTPS則是具有安全性的SSL加密傳輸協議。
- HTTPS和HTTP使用的是完全不同的連接方式,用的端口也不一樣,HTTP是80,HTTPS是443。
- HTTP的連接很簡單,是無狀態的,HTTPS是HTTP+SSL協議構建的,可進行加密傳輸、身份認證的網絡協議,比HTTP協議安全。
2.HTTPS的加密過程:
①客戶端首次發出請求包含以下內容:
- 支持的協議版本,比如TLS 1.0版本
- 一個客戶端生成的隨機數,稍后用于生成"對話密鑰"
- 支持的加密方法,比如RSA公鑰加密
- 支持的壓縮方法
客戶端發送的信息之中不包括服務器的域名,也就是說,理論上服務器只能包含一個網站,否則會分不清應該向客戶端提供哪一個網站的提供的數字證書。這就是為什么通常一臺服務器只能由一張數字證書的原因
對于虛擬主機的用戶來說,這當然很不方便。2006年,TLS協議加入了Server Name Indication擴展,允許客戶端向服務器提供它所請求的域名。
②服務器收到請求首次回應:
- 協議的版本,比如TLS1.0版本,如果瀏覽器與服務器支持的版本不一致,服務器關閉加密通信
- 加密的算法
- 隨機數
- 服務器證書(也就是非對稱加密的公鑰)
采用HTTPS協議的服務器必須要有一套數字證書,可以是自己制作或者CA證書。區別就是自己制作的證書需要客戶端驗證通過,才可以繼續訪問,而使用CA證書則直接去證書機構驗證請求。這套證書其實就是一堆公鑰和私鑰。公鑰給別人加密使用,私鑰給自己解密使用。服務器在接收到客戶端的請求后,服務器需要確定加密協議的版本,以及加密的算法,然后也生成一個隨機數。
③客戶端驗證證書:
- 首先驗證證書的安全性
- 驗證通過之后,客戶端會生成一個隨機數pre-master secret,然后使用證書中的公鑰進行加密,然后傳遞給服務器端(將客戶端生成的對稱加密秘鑰用服務器傳下來的公鑰進行加密)
④服務器收到加密信息
服務器收到使用公鑰加密的內容,在服務器端使用私鑰解密之后獲得隨機數pre-master secret,然后根據radom1、radom2、pre-master secret通過一定的算法得出一個對稱加密的秘鑰,作為后面交互過程中使用對稱秘鑰。同時客戶端也會使用radom1、radom2、pre-master secret,和同樣的算法生成對稱秘鑰。
⑤服務器最后的回應
服務器生成"會話密鑰"后,向客戶端最后發送下面信息:
1、編碼改變通知,表示隨后的信息都將用雙方商定的加密方法和密鑰發送。
2、服務器握手結束通知,表示服務器握手階段已經結束。這一項同時也是前面所有內容的hash值,用來供客戶端校驗。
⑥客戶端解密
客戶端用之前生成的私鑰解密服務器傳過來的信息,于是獲取了解密后的內容。
至此,整個握手階段全部結束了。再后續的交互中就使用上一步生成的對稱秘鑰對傳輸的內容進行加密和解密,就完全是使用普通HTTP協議,只不過用"會話密鑰"加密內容。
上面產生的隨機數,是整個握手階段的出現的第三個隨機數,又稱"pre-master key"。有了它之后,客戶端和服務器同時有了三個隨機數,接著雙方就用事先協商的加密方法,各自生成本地會話所用的同一把"會話密鑰"。
為什么一定要用三個隨機數,來生成"會話密鑰"?
答:不管是客戶端還是服務器,都是下需要隨機數,這樣生成的密鑰才不會每次都一樣,由于SSL協議中證書是靜態的,因此十分有必要引入一種隨機因素來保證協商出的密鑰的隨機性。
對于RSA密鑰交換算法來說,pre-master-key本身就是一個隨機數,再加上第一步、第三步消息中的隨機數,三個隨機數通過一個密鑰導出器最終導出一個對稱密鑰。pre master 的存在在于SSL協議不信任每一個主機都能產生完全的隨機數,如果隨機數不隨機,那么pre master secret就可能被猜出來,那么僅適用于pre master secret作為密鑰就不合適了,因此必須引入新的隨機因素,那么客戶端和服務器加上pre master secret三個隨機數一同生成的密鑰就不容易被猜出了,一個偽隨機數可能完全不隨機,但是三個偽隨機就十分接近隨機了,每增加一個自由度,隨機性增加的可不是一。
3.HTTPS的優點和缺點
①優點:
- 內容加密,建立一個信息的安全通道,來保證數據傳輸過程的安全性。
- 身份認證,確認網站的真是性。
- 數據完整性,防止內容被第三方冒充或者篡改。
②缺點: - 于要對數據進行加密,認證,所以注定他會比HTTP慢,當然現在也有很多優化。
處于安全考慮,瀏覽器是不會再本地保存HTTPS緩存。實際上,只要在HTTP頭中使用特定的命令,HTTPS是可以被緩存的。Firefox默認只在內存中緩存HTTS。但是,只要在請求頭中有Cache-Control:Public,緩存就會被寫到磁盤上,IE只要http頭允許就可以緩存https內容,緩存策略與是否使用HTTPS協議無關。
四.TCP相關
TCP面向連接,提供可靠的數據傳輸。在這一層,我們通常都是通過Socket Api來操作TCP,建立連接等等。
1、三次握手建立連接
第一次:發送SNY=1表示此次握手是請求建立連接的,然后seq生成一個客戶端的隨機數X
第二次:發送SNY=1,ACK=1表示是回復請求建立連接的,然后ack=客戶端的seq+1(這樣客戶端收到后就能確認是之前想要連接的那個服務端),然后把服務端也生成一個代表自己的隨機數seq=Y發給客戶端。
第三次:ACK=1。 seq=客戶端隨機數+1,ack=服務端隨機數+1(這樣服務端就知道是剛剛那個客戶端了)
為什么建立連接需要三次握手?
第三次握手是為了防止已經失效的連接請求報文段突然又傳到服務端,因而產生錯誤
具體情況就是:C端發出去的第一個網絡連接請求由于某些原因在網絡節點中滯留了,導致延遲,直到連接釋放的某個時間點才到達S端,這是一個早已失效的報文,但是此時S端仍然認為這是C端的建立連接請求第一次握手,于是S端回應了C端,第二次握手。如果只有兩次握手,那么到這里,連接就建立了,但是此時C端并沒有任何數據要發送,而S端就會傻傻的等待著,造成很大的資源浪費。所以需要第三次握手,只有C端再次回應一下,就可以避免這種情況。
2、四次握手斷開連接
為什么比建立連接時多了一次握手?
可以看到這里服務端的ACK(回復客戶端)和FIN(終止)消息并不是同時發出的,而是先ACK,然后再FIN,這也很好理解,當客戶端要求斷開連接時,此時服務端可能還有未發送完的數據,所以先ACK,然后等數據發送完再FIN。這樣就變成了四次握手了。
大致意思:
Client:我要斷開連接了
Server:我收到你的消息了
Server:我也要斷開連接了
Client:收到你要斷開連接的消息了
3、TCP和UDP的區別
TCP (傳輸控制協議)
- 建立連接,形成傳輸數據的通道
- 在連接中進行大數據傳輸(數據大小不收限制)
- 通過三次握手完成連接,是可靠協議,安全送達
- 必須建立連接,效率會稍低
UDP (用戶數據報協議)
- 將數據及源和目的封裝成數據包中,不需要建立連接
- 每個數據報的大小限制在64K之內
- 因為無需連接,因此是不可靠協議
- 不需要建立連接,速度快
五.Socket
Socket是一組操作TCP/UDP的API,像HttpURLConnection和Okhttp這種涉及到比較底層的網絡請求發送的,最終當然也都是通過Socket來進行網絡請求連接發送,而像Volley、Retrofit則是更上層的封裝,最后是依靠HttpURLConnection或者Okhttp來進行最終的連接建立和請求發送。
Socket的簡單使用的話應該都會,兩個端各建立一個Socket,服務端的叫ServerSocket,然后建立連接即可。
六特別感謝:
https://juejin.im/post/5b49f9fbf265da0f563dc9d8
http://www.lxweimin.com/p/116ebf3034d9