網(wǎng)絡(luò)一直是項(xiàng)目里比較重要的一個(gè)模塊,Android開源項(xiàng)目上出現(xiàn)過很多優(yōu)秀的網(wǎng)絡(luò)框架。從一開始只是一些對HttpClient和HttpUrlConnection簡易封裝使用的工具類,到后來Google開源的比較完善豐富的Volley,再到如今比較流行的Okhttp、Retrofit。他們之間存在異同,這個(gè)系列主要想通過對網(wǎng)絡(luò)基礎(chǔ)知識、Android網(wǎng)絡(luò)框架的解析來理清他們的關(guān)系以及原理。
一.計(jì)算機(jī)網(wǎng)絡(luò)體系結(jié)構(gòu)
每個(gè)程序員的基本知識,OSI的七層模型:

其中表示層和會話層沒有協(xié)議,所以我們重點(diǎn)解釋一下其他5層作用
1.應(yīng)用層:如http協(xié)議,它實(shí)際上是定義了如何包裝和解析數(shù)據(jù),應(yīng)用層是http協(xié)議的話,則會按照協(xié)議規(guī)定包裝數(shù)據(jù),如按照請求行、請求頭、請求體包裝,包裝好數(shù)據(jù)后將數(shù)據(jù)傳至運(yùn)輸層。
2.傳輸層:運(yùn)輸層有TCP和UDP兩種協(xié)議,分別對應(yīng)可靠的運(yùn)輸和不可靠的運(yùn)輸,如TCP因?yàn)橐峁┛煽康膫鬏?,所以?nèi)部要解決如何建立連接、如何保證傳輸是可靠的不丟數(shù)據(jù)、如何調(diào)節(jié)流量控制和擁塞控制。關(guān)于這一層,我們平常一般都是和Socket打交道,Socket是一組封裝的編程調(diào)用接口,通過它,我們就能操作TCP、UDP進(jìn)行連接的建立等。我們平常使用Socket進(jìn)行連接建立的時(shí)候,一般都要指定端口號,所以這一層指定了把數(shù)據(jù)送到對應(yīng)的端口號。
3.網(wǎng)絡(luò)層:這一層IP協(xié)議,以及一些路由選擇協(xié)議等等,所以這一層的指定了數(shù)據(jù)要傳輸?shù)侥膫€(gè)IP地址。中間涉及到一些最優(yōu)線路,路由選擇算法等等。
4.數(shù)據(jù)鏈路層:印象比較深的就是ARP協(xié)議,負(fù)責(zé)把IP地址解析為MAC地址,即硬件地址,這樣就找到了對應(yīng)的唯一的機(jī)器。
5.物理層:這一層就是最底層了,提供二進(jìn)制流傳輸服務(wù),也就是也就是真正開始通過傳輸介質(zhì)(有線、無線)開始進(jìn)行數(shù)據(jù)的傳輸了。
所以通過上面五層的各司其職,實(shí)現(xiàn)物理傳輸介質(zhì)--MAC地址--IP地址--端口號--獲取到數(shù)據(jù)根據(jù)應(yīng)用層協(xié)議解析數(shù)據(jù)最終實(shí)現(xiàn)了網(wǎng)絡(luò)通信和數(shù)據(jù)傳輸。
TCP和UDP使用IP協(xié)議從一個(gè)網(wǎng)絡(luò)傳送數(shù)據(jù)包到另一個(gè)網(wǎng)絡(luò)。把IP想像成一種高速公路,它允許其它協(xié)議在上面行駛并找到到其它電腦的出口。TCP和UDP是高速公路上的“卡車”,它們攜帶的貨物就是像HTTP,文件傳輸協(xié)議FTP這樣的協(xié)議等。
二.HTTP相關(guān)
1.HTTP是無連接無狀態(tài)的。
無連接:并不是說不需要連接,Http協(xié)議只是一個(gè)應(yīng)用層協(xié)議,最終還是要靠運(yùn)輸層的如TCP協(xié)議向上提供的服務(wù)進(jìn)行連接。無連接的含義是http約定了每次連接只處理一個(gè)請求,一次請求完成后就斷開連接,這樣主要是為了緩解服務(wù)器的壓力,減小連接對服務(wù)器資源的占用。我的理解是,建立連接實(shí)際上是運(yùn)輸層的事,面向應(yīng)用層的http來說的話,它就是無連接的,因?yàn)樯蠈訉ο聦訜o感知。
無狀態(tài):每個(gè)請求之間都是獨(dú)立的,對于之前的請求事務(wù)沒有記憶的能力。所以就出現(xiàn)了像
Cookie這種,用來保存一些狀態(tài)的東西。
2.請求報(bào)文與響應(yīng)報(bào)文

- 關(guān)于Get和Post的區(qū)別:
1.Get會把請求參數(shù)都拼接在url后面,最終顯示在地址欄,而Post則會把請求參數(shù)數(shù)據(jù)放進(jìn)請求體中,不會再地址欄顯示出來
2.傳遞參數(shù)的長度限制,Get請求URL 的最大長度是 2048 個(gè)字符,Post無限制。
2.HTTP的緩存機(jī)制
Http的緩存主要利用header里的兩個(gè)字段來控制:
① Cache-control主要包含以及幾個(gè)字段:
- private:則只有客戶端可以緩存
- public:客戶端和代理服務(wù)器都可以緩存
- max-age:緩存的過期時(shí)間
- no-cache:代表不緩沖過期的資源,緩存會向源服務(wù)器進(jìn)行有效確認(rèn)
- no-store:所有內(nèi)存都不會進(jìn)行緩存
②ETag:即用來進(jìn)行對比緩存,Etag是服務(wù)端資源的一個(gè)標(biāo)識碼
當(dāng)客戶端發(fā)送第一次請求時(shí)服務(wù)端會下發(fā)當(dāng)前請求資源的標(biāo)識碼Etag,下次再請求時(shí),客戶端則會通過header里的If-None-Match將這個(gè)標(biāo)識碼Etag帶上,服務(wù)端將客戶端傳來的Etag與最新的資源Etag做對比,如果一樣,則表示資源沒有更新,返回304。
通過Cache-control和Etag的配合來實(shí)現(xiàn)Http的緩存機(jī)制。
4.,Http2.0相對于Http1.x的對比:
khttp支持配置使用Http 2.0協(xié)議,Http2.0相對于Http1.x來說提升是巨大的,主要有以下幾點(diǎn):
二進(jìn)制格式:http1.x是文本協(xié)議,而http2.0是二進(jìn)制以幀為基本單位,是一個(gè)二進(jìn)制協(xié)議,一幀中除了包含數(shù)據(jù)外同時(shí)還包含該幀的標(biāo)識:Stream Identifier,即標(biāo)識了該幀屬于哪個(gè)request,使得網(wǎng)絡(luò)傳輸變得十分靈活。
多路復(fù)用:一個(gè)很大的改進(jìn),原先http1.x一個(gè)連接一個(gè)請求的情況有比較大的局限性,也引發(fā)了很多問題,如建立多個(gè)連接的消耗以及效率問題。
http1.x為了解決效率問題,可能會盡量多的發(fā)起并發(fā)的請求去加載資源,然而瀏覽器對于同一域名下的并發(fā)請求有限制,而優(yōu)化的手段一般是將請求的資源放到不同的域名下來突破這種限制。
而http2.0支持的多路復(fù)用可以很好的解決這個(gè)問題,多個(gè)請求共用一個(gè)TCP連接,多個(gè)請求可以同時(shí)在這個(gè)TCP連接上并發(fā),一個(gè)是解決了建立多個(gè)TCP連接的消耗問題,一個(gè)也解決了效率的問題。那么是什么原理支撐多個(gè)請求可以在一個(gè)TCP連接上并發(fā)呢?基本原理就是上面的二進(jìn)制分幀,因?yàn)槊恳粠加幸粋€(gè)身份標(biāo)識,所以多個(gè)請求的不同幀可以并發(fā)的無序發(fā)送出去,在服務(wù)端會根據(jù)每一幀的身份標(biāo)識,將其整理到對應(yīng)的request中。
header頭部壓縮:主要是通過壓縮header來減少請求的大小,減少流量消耗,提高效率。因?yàn)橹按嬖谝粋€(gè)問題是,每次請求都要帶上header,而這個(gè)header中的數(shù)據(jù)通常是一層不變的。
支持服務(wù)端推送
4.HTTP的缺點(diǎn)
- 通信使用明文(不加密),內(nèi)容可能被竊聽(抓包工具可以獲取請求和響應(yīng)內(nèi)容)
- 不驗(yàn)證通訊方的身分,任何人都坑你發(fā)送請求,不管對方是誰都返回相應(yīng)
- 無法證明報(bào)文的完整性,可能會遭到篡改,即沒有辦法確認(rèn)發(fā)出的請求/相應(yīng)前后一致。
三.HTTPS
http是超文本傳輸協(xié)議,而https可以簡單理解為安全的http協(xié)議。https通過在http協(xié)議下添加了一層ssl協(xié)議對數(shù)據(jù)進(jìn)行加密從而保證了安全。https的作用主要有兩點(diǎn):
- 建立安全的信息傳輸通道,保證數(shù)據(jù)傳輸安全;
- 確認(rèn)網(wǎng)站的真實(shí)性。
而非對稱加密算法之所以能實(shí)現(xiàn)安全傳輸?shù)暮诵木A就是:
公鑰加密的信息只能用私鑰解開,私鑰加密的信息只能被公鑰解開
對稱加密(也叫私鑰加密):加密和解密用的都是相同的秘鑰,優(yōu)點(diǎn)是速度快,缺點(diǎn)是安全性低。
常見的對稱加密算法有DES、AES、RC4、IDEA。
非對稱加密:非對稱加密有一個(gè)秘鑰對,分為公鑰和私鑰。一般來說,私鑰自己持有,公鑰可以公開給對方,優(yōu)點(diǎn)是安全性比對稱加密高,缺點(diǎn)是數(shù)據(jù)傳輸效率比對稱加密低。采用公鑰加密的信息只有對應(yīng)的私鑰可以解密。常見的非對稱加密包括RSA、DSA/DSS等。
對于Https是對稱加密和非對稱加密結(jié)合使用,使用非對稱加密完成秘鑰的傳遞,然后使用對稱秘鑰進(jìn)行數(shù)據(jù)加密和解密。二者結(jié)合既保證了安全性,又提高了數(shù)據(jù)傳輸效率。
1.HTTP與HTTPS的相同和異同點(diǎn)
①、HTTP與HTTPS的相同點(diǎn):
大多數(shù)情況下,HTTP和HTTPS是相同的,因此都采用同一個(gè)基礎(chǔ)協(xié)議,作為HTTP或者HTTPS客戶端--瀏覽器/app等,設(shè)置一個(gè)連接到web服務(wù)器指定的寬口。當(dāng)服務(wù)器接收到請求,它會返回一個(gè)狀態(tài)碼以及消息,這個(gè)回應(yīng)可能是請求信息、或者指示某個(gè)錯(cuò)誤發(fā)送的錯(cuò)誤信息。系統(tǒng)使用統(tǒng)一資源定位符URI,因此資源可以被唯一指定。在表面上HTTPS和HTTP唯一不同的只是一個(gè)協(xié)議頭HTTPS的說明,其他都一樣。
②、HTTP與HTTPS的不同點(diǎn):
- HTTPS需要用到CA申請證書。
- HTTP是超文本傳輸協(xié)議,信息是明文的;HTTPS則是具有安全性的SSL加密傳輸協(xié)議。
- HTTPS和HTTP使用的是完全不同的連接方式,用的端口也不一樣,HTTP是80,HTTPS是443。
- HTTP的連接很簡單,是無狀態(tài)的,HTTPS是HTTP+SSL協(xié)議構(gòu)建的,可進(jìn)行加密傳輸、身份認(rèn)證的網(wǎng)絡(luò)協(xié)議,比HTTP協(xié)議安全。
2.HTTPS的加密過程:
①客戶端首次發(fā)出請求包含以下內(nèi)容:
- 支持的協(xié)議版本,比如TLS 1.0版本
- 一個(gè)客戶端生成的隨機(jī)數(shù),稍后用于生成"對話密鑰"
- 支持的加密方法,比如RSA公鑰加密
- 支持的壓縮方法
客戶端發(fā)送的信息之中不包括服務(wù)器的域名,也就是說,理論上服務(wù)器只能包含一個(gè)網(wǎng)站,否則會分不清應(yīng)該向客戶端提供哪一個(gè)網(wǎng)站的提供的數(shù)字證書。這就是為什么通常一臺服務(wù)器只能由一張數(shù)字證書的原因
對于虛擬主機(jī)的用戶來說,這當(dāng)然很不方便。2006年,TLS協(xié)議加入了Server Name Indication擴(kuò)展,允許客戶端向服務(wù)器提供它所請求的域名。
②服務(wù)器收到請求首次回應(yīng):
- 協(xié)議的版本,比如TLS1.0版本,如果瀏覽器與服務(wù)器支持的版本不一致,服務(wù)器關(guān)閉加密通信
- 加密的算法
- 隨機(jī)數(shù)
- 服務(wù)器證書(也就是非對稱加密的公鑰)
采用HTTPS協(xié)議的服務(wù)器必須要有一套數(shù)字證書,可以是自己制作或者CA證書。區(qū)別就是自己制作的證書需要客戶端驗(yàn)證通過,才可以繼續(xù)訪問,而使用CA證書則直接去證書機(jī)構(gòu)驗(yàn)證請求。這套證書其實(shí)就是一堆公鑰和私鑰。公鑰給別人加密使用,私鑰給自己解密使用。服務(wù)器在接收到客戶端的請求后,服務(wù)器需要確定加密協(xié)議的版本,以及加密的算法,然后也生成一個(gè)隨機(jī)數(shù)。
③客戶端驗(yàn)證證書:
- 首先驗(yàn)證證書的安全性
- 驗(yàn)證通過之后,客戶端會生成一個(gè)隨機(jī)數(shù)pre-master secret,然后使用證書中的公鑰進(jìn)行加密,然后傳遞給服務(wù)器端(將客戶端生成的對稱加密秘鑰用服務(wù)器傳下來的公鑰進(jìn)行加密)
④服務(wù)器收到加密信息
服務(wù)器收到使用公鑰加密的內(nèi)容,在服務(wù)器端使用私鑰解密之后獲得隨機(jī)數(shù)pre-master secret,然后根據(jù)radom1、radom2、pre-master secret通過一定的算法得出一個(gè)對稱加密的秘鑰,作為后面交互過程中使用對稱秘鑰。同時(shí)客戶端也會使用radom1、radom2、pre-master secret,和同樣的算法生成對稱秘鑰。
⑤服務(wù)器最后的回應(yīng)
服務(wù)器生成"會話密鑰"后,向客戶端最后發(fā)送下面信息:
1、編碼改變通知,表示隨后的信息都將用雙方商定的加密方法和密鑰發(fā)送。
2、服務(wù)器握手結(jié)束通知,表示服務(wù)器握手階段已經(jīng)結(jié)束。這一項(xiàng)同時(shí)也是前面所有內(nèi)容的hash值,用來供客戶端校驗(yàn)。
⑥客戶端解密
客戶端用之前生成的私鑰解密服務(wù)器傳過來的信息,于是獲取了解密后的內(nèi)容。
至此,整個(gè)握手階段全部結(jié)束了。再后續(xù)的交互中就使用上一步生成的對稱秘鑰對傳輸?shù)膬?nèi)容進(jìn)行加密和解密,就完全是使用普通HTTP協(xié)議,只不過用"會話密鑰"加密內(nèi)容。
上面產(chǎn)生的隨機(jī)數(shù),是整個(gè)握手階段的出現(xiàn)的第三個(gè)隨機(jī)數(shù),又稱"pre-master key"。有了它之后,客戶端和服務(wù)器同時(shí)有了三個(gè)隨機(jī)數(shù),接著雙方就用事先協(xié)商的加密方法,各自生成本地會話所用的同一把"會話密鑰"。
為什么一定要用三個(gè)隨機(jī)數(shù),來生成"會話密鑰"?
答:不管是客戶端還是服務(wù)器,都是下需要隨機(jī)數(shù),這樣生成的密鑰才不會每次都一樣,由于SSL協(xié)議中證書是靜態(tài)的,因此十分有必要引入一種隨機(jī)因素來保證協(xié)商出的密鑰的隨機(jī)性。
對于RSA密鑰交換算法來說,pre-master-key本身就是一個(gè)隨機(jī)數(shù),再加上第一步、第三步消息中的隨機(jī)數(shù),三個(gè)隨機(jī)數(shù)通過一個(gè)密鑰導(dǎo)出器最終導(dǎo)出一個(gè)對稱密鑰。pre master 的存在在于SSL協(xié)議不信任每一個(gè)主機(jī)都能產(chǎn)生完全的隨機(jī)數(shù),如果隨機(jī)數(shù)不隨機(jī),那么pre master secret就可能被猜出來,那么僅適用于pre master secret作為密鑰就不合適了,因此必須引入新的隨機(jī)因素,那么客戶端和服務(wù)器加上pre master secret三個(gè)隨機(jī)數(shù)一同生成的密鑰就不容易被猜出了,一個(gè)偽隨機(jī)數(shù)可能完全不隨機(jī),但是三個(gè)偽隨機(jī)就十分接近隨機(jī)了,每增加一個(gè)自由度,隨機(jī)性增加的可不是一。
3.HTTPS的優(yōu)點(diǎn)和缺點(diǎn)
①優(yōu)點(diǎn):
- 內(nèi)容加密,建立一個(gè)信息的安全通道,來保證數(shù)據(jù)傳輸過程的安全性。
- 身份認(rèn)證,確認(rèn)網(wǎng)站的真是性。
- 數(shù)據(jù)完整性,防止內(nèi)容被第三方冒充或者篡改。
②缺點(diǎn): - 于要對數(shù)據(jù)進(jìn)行加密,認(rèn)證,所以注定他會比HTTP慢,當(dāng)然現(xiàn)在也有很多優(yōu)化。
處于安全考慮,瀏覽器是不會再本地保存HTTPS緩存。實(shí)際上,只要在HTTP頭中使用特定的命令,HTTPS是可以被緩存的。Firefox默認(rèn)只在內(nèi)存中緩存HTTS。但是,只要在請求頭中有Cache-Control:Public,緩存就會被寫到磁盤上,IE只要http頭允許就可以緩存https內(nèi)容,緩存策略與是否使用HTTPS協(xié)議無關(guān)。
四.TCP相關(guān)
TCP面向連接,提供可靠的數(shù)據(jù)傳輸。在這一層,我們通常都是通過Socket Api來操作TCP,建立連接等等。
1、三次握手建立連接

第一次:發(fā)送SNY=1表示此次握手是請求建立連接的,然后seq生成一個(gè)客戶端的隨機(jī)數(shù)X
第二次:發(fā)送SNY=1,ACK=1表示是回復(fù)請求建立連接的,然后ack=客戶端的seq+1(這樣客戶端收到后就能確認(rèn)是之前想要連接的那個(gè)服務(wù)端),然后把服務(wù)端也生成一個(gè)代表自己的隨機(jī)數(shù)seq=Y發(fā)給客戶端。
第三次:ACK=1。 seq=客戶端隨機(jī)數(shù)+1,ack=服務(wù)端隨機(jī)數(shù)+1(這樣服務(wù)端就知道是剛剛那個(gè)客戶端了)
為什么建立連接需要三次握手?
第三次握手是為了防止已經(jīng)失效的連接請求報(bào)文段突然又傳到服務(wù)端,因而產(chǎn)生錯(cuò)誤
具體情況就是:C端發(fā)出去的第一個(gè)網(wǎng)絡(luò)連接請求由于某些原因在網(wǎng)絡(luò)節(jié)點(diǎn)中滯留了,導(dǎo)致延遲,直到連接釋放的某個(gè)時(shí)間點(diǎn)才到達(dá)S端,這是一個(gè)早已失效的報(bào)文,但是此時(shí)S端仍然認(rèn)為這是C端的建立連接請求第一次握手,于是S端回應(yīng)了C端,第二次握手。如果只有兩次握手,那么到這里,連接就建立了,但是此時(shí)C端并沒有任何數(shù)據(jù)要發(fā)送,而S端就會傻傻的等待著,造成很大的資源浪費(fèi)。所以需要第三次握手,只有C端再次回應(yīng)一下,就可以避免這種情況。
2、四次握手?jǐn)嚅_連接

為什么比建立連接時(shí)多了一次握手?
可以看到這里服務(wù)端的ACK(回復(fù)客戶端)和FIN(終止)消息并不是同時(shí)發(fā)出的,而是先ACK,然后再FIN,這也很好理解,當(dāng)客戶端要求斷開連接時(shí),此時(shí)服務(wù)端可能還有未發(fā)送完的數(shù)據(jù),所以先ACK,然后等數(shù)據(jù)發(fā)送完再FIN。這樣就變成了四次握手了。
大致意思:
Client:我要斷開連接了
Server:我收到你的消息了
Server:我也要斷開連接了
Client:收到你要斷開連接的消息了
3、TCP和UDP的區(qū)別
TCP (傳輸控制協(xié)議)
- 建立連接,形成傳輸數(shù)據(jù)的通道
- 在連接中進(jìn)行大數(shù)據(jù)傳輸(數(shù)據(jù)大小不收限制)
- 通過三次握手完成連接,是可靠協(xié)議,安全送達(dá)
- 必須建立連接,效率會稍低
UDP (用戶數(shù)據(jù)報(bào)協(xié)議)
- 將數(shù)據(jù)及源和目的封裝成數(shù)據(jù)包中,不需要建立連接
- 每個(gè)數(shù)據(jù)報(bào)的大小限制在64K之內(nèi)
- 因?yàn)闊o需連接,因此是不可靠協(xié)議
- 不需要建立連接,速度快
五.Socket
Socket是一組操作TCP/UDP的API,像HttpURLConnection和Okhttp這種涉及到比較底層的網(wǎng)絡(luò)請求發(fā)送的,最終當(dāng)然也都是通過Socket來進(jìn)行網(wǎng)絡(luò)請求連接發(fā)送,而像Volley、Retrofit則是更上層的封裝,最后是依靠HttpURLConnection或者Okhttp來進(jìn)行最終的連接建立和請求發(fā)送。
Socket的簡單使用的話應(yīng)該都會,兩個(gè)端各建立一個(gè)Socket,服務(wù)端的叫ServerSocket,然后建立連接即可。
六特別感謝:
https://juejin.im/post/5b49f9fbf265da0f563dc9d8
http://www.itdecent.cn/p/116ebf3034d9