成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

邁向高階:優秀Android程序員必知必會的網絡基礎

移動開發 Android
事實證明在Android的日常開發和源碼閱讀中也會經常碰到相關知識,掌握這些網絡基礎知識,也是Android程序員真正邁向高階的過程中必備的一些基本技術素質之一。有鑒于此,本文將主要介紹計算機網絡的一些基礎,以及在Android開發中的一些使用及遇到的問題和解決。

1、前言

網絡通信一直是Android項目里比較重要的一個模塊,Android開源項目上出現過很多優秀的網絡框架,從一開始只是一些對HttpClient和HttpUrlConnection簡易封裝使用的工具類,到后來Google開源的比較完善豐富的Volley,再到如今比較流行的Okhttp、Retrofit。

要想理解他們之間存在的異同(或者具體點說,要想更深入地掌握Android開發中的網絡通信技術),必須對網絡基礎知識、Android網絡框架的基本原理等做到心中有數、信手拈來,關鍵時刻才能找到適合您APP的最佳網絡通信技術實踐。

邁向高階:優秀Android程序員必知必會的網絡基礎

事實證明在Android的日常開發和源碼閱讀中也會經常碰到相關知識,掌握這些網絡基礎知識,也是Android程序員真正邁向高階的過程中必備的一些基本技術素質之一。

有鑒于此,本文將主要介紹計算機網絡的一些基礎,以及在Android開發中的一些使用及遇到的問題和解決。

本篇主要分為以下幾部分:

  • 1)計算機網絡體系結構;
  • 2)Http相關;
  • 3)Tcp相關;
  • 4)Socket。

2、關于作者

舒大飛:攜程網Android開發工程師。

注:在收錄本文時,為了更易于理解,對內容做了更為細致的修訂。

3、計算機網絡體系結構

計算機網絡體系結構,即經常看到的計算機網絡體系的分層結構,理清這個還是有必要的,防止對Http和Tcp兩個根本不在同一層的協議糾纏不清。 根據不同的參考模型,分層結構有幾個不同的版本,如OSI模型以及TCP/IP模型。

下面就以比較經常看到的的5層結構為例: 

如上圖所示,五層的體系結構至上往下,最終可以實現端對端之間的數據傳輸與通信,他們各自負責一些什么,最終如何實現端對端之間的通信?

  • 應用層:如http協議,它實際上是定義了如何包裝和解析數據,應用層是http協議的話,則會按照協議規定包裝數據,如按照請求行、請求頭、請求體包裝,包裝好數據后將數據傳至運輸層。
  • 運輸層:運輸層有TCP和UDP兩種協議,分別對應可靠的運輸和不可靠的運輸,如TCP因為要提供可靠的傳輸,所以內部要解決如何建立連接、如何保證傳輸是可靠的不丟數據、如何調節流量控制和擁塞控制。關于這一層,我們平常一般都是和Socket打交道,Socket是一組封裝的編程調用接口,通過它,我們就能操作TCP、UDP進行連接的建立等。我們平常使用Socket進行連接建立的時候,一般都要指定端口號,所以這一層指定了把數據送到對應的端口號。
  • 網絡層:這一層IP協議,以及一些路由選擇協議等等,所以這一層的指定了數據要傳輸到哪個IP地址。中間涉及到一些最優線路,路由選擇算法等等。
  • 數據鏈路層:印象比較深的就是ARP協議,負責把IP地址解析為MAC地址,即硬件地址,這樣就找到了對應的唯一的機器。
  • 物理層:這一層就是最底層了,提供二進制流傳輸服務,也就是也就是真正開始通過傳輸介質(有線、無線)開始進行數據的傳輸了。

所以通過上面五層的各司其職,實現物理傳輸介質--MAC地址--IP地址--端口號--獲取到數據根據應用層協議解析數據最終實現了網絡通信和數據傳輸。

下面會著重講一下HTTP和TCP相關的東西。

4、HTTP相關

本節主要講一些關于Http的基礎知識,以及在Android中的一些實際應用和碰到的問題和解決。

4.1 正確理解HTTP的“無連接”“與無狀態”

Http是無連接無狀態的。

無連接并不是說不需要連接,Http協議只是一個應用層協議,最終還是要靠運輸層的如TCP協議向上提供的服務進行連接。

無連接的含義是http約定了每次連接只處理一個請求,一次請求完成后就斷開連接,這樣主要是為了緩解服務器的壓力,減小連接對服務器資源的占用。我的理解是,建立連接實際上是運輸層的事,面向應用層的http來說的話,它就是無連接的,因為上層對下層無感知。

無狀態的指每個請求之間都是獨立的,對于之前的請求事務沒有記憶的能力。所以就出現了像Cookie這種,用來保存一些狀態的東西。

4.2 請求報文與響應報文

這里主要簡單說一下HTTP請求報文和響應報文的格式方面的基礎知識。

請求報文: 

響應報文: 

關于Get和Post,我們都熟知的關于Get和Post的區別大致有以下幾點:

  • Get會把請求參數都拼接在url后面,最終顯示在地址欄,而Post則會把請求參數數據放進請求體中,不會再地址欄顯示出來;
  • 傳遞參數的長度限制。

問題:

  • 對于第1)點,如果是在瀏覽器里把隱私數據暴露在地址欄上確實不妥,但是如果是在App開發中呢,沒有地址欄的概念,那么這一點是不是還會成為選擇post還是get的制約條件;
  • 對于第2)點,長度的限制應該是瀏覽器的限制,跟get本身無關,如果是在App開發中,這一點是否也可以忽略。

4.3 HTTP的緩存機制

之所以想介紹以下Http的緩存機制,是因為Okhttp中對于網絡請求緩存這一塊就是利用了Http的的緩存機制,而不是像Volley等框架那樣客戶端完全自己寫一套緩存策略自己玩。

Http的緩存主要利用header里的兩個字段來控制:即Cache-control和ETag,下面將分別來介紹。

1)Cache-control主要包含以及幾個字段:

  • private:則只有客戶端可以緩存;
  • public:客戶端和代理服務器都可以緩存;
  • max-age:緩存的過期時間;
  • no-cache:需要使用對比緩存來驗證緩存數據;
  • no-store:所有內存都不會進行緩存。

實際上就是在這里面設置了一個緩存策略,由服務端第一次通過header下發給客戶端,可以看到:

  • max-age:即緩存過期的時間,則之后再次請求,如果沒有超過緩存失效的時間則可以直接使用緩存;
  • no-cache:表示需要使用對比緩存來驗證緩存數據,如果這個字段是打開的,則就算max-age緩存沒有失效,則還是需要發起一次請求向服務端確認一下資源是否有更新,是否需要重新請求數據,至于怎么做對比緩存,就是下面要說的Etag的作用。如果服務端確認資源沒有更新,則返回304,取本地緩存即可,如果有更新,則返回最新的資源;
  • no-store:這個字段打開,則不會進行緩存,也不會取緩存。

2)ETag:即用來進行對比緩存,Etag是服務端資源的一個標識碼

當客戶端發送第一次請求時服務端會下發當前請求資源的標識碼Etag,下次再請求時,客戶端則會通過header里的If-None-Match將這個標識碼Etag帶上,服務端將客戶端傳來的Etag與最新的資源Etag做對比,如果一樣,則表示資源沒有更新,返回304。

3)小結:

通過Cache-control和Etag的配合來實現Http的緩存機制。

4.4 HTTP的Cookie

上面說了Http協議是無狀態的,而Cookie就是用來在本地緩存記住一些狀態的,一個Cookie一般都包含domin(所屬域)、path、Expires(過期時間)等幾個屬性。服務端可以通過在響應頭里的set-cookies來將狀態寫入客戶端的Cookie里。下次客戶端發起請求時可以將Cookie帶上。

Android開發中遇到的問題及解決:

說起Cookie,一般如果平常只是做App開發,比較不經常遇到,但是如果是涉及到WebView的需求,則有可能會遇到。

下面就說一下我在項目里遇到過的一個關于WebView Cookie的揪心往事:需求是這樣的,加載的WebView中的H5頁面需要是已登錄狀態的,所以我們需要在原生頁面登錄后,手動將ticket寫入WebView的Cookie,之后WebView里加載的H5頁面帶著Cookie里的ticket給服務端驗證通過就好了。

但是遇到一個問題:通過Chrome inspect調試WebView,手動寫的Cookie確實是已經寫進去了,但是發起請求的時候,Cookie就是沒有帶上,導致請求驗證失敗,之后通過排查,是WebView的屬性默認關閉引起,通過下面的代碼設置打開即可:

  1. CookieManager cookieManager = CookieManager.getInstance();  
  2. if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {  
  3. cookieManager.setAcceptThirdPartyCookies(mWebView, true);  
  4. else 
  5. cookieManager.setAcceptCookie(true);  

4.5 Https

我們都知道Https保證了我們數據傳輸的安全,Https=Http+Ssl,之所以能保證安全主要的原理就是利用了非對稱加密算法,平常用的對稱加密算法之所以不安全,是因為雙方是用統一的密匙進行加密解密的,只要雙方任意一方泄漏了密匙,那么其他人就可以利用密匙解密數據。

而非對稱加密算法之所以能實現安全傳輸的核心精華就是:公鑰加密的信息只能用私鑰解開,私鑰加密的信息只能被公鑰解開。

1)簡述非對稱加密算法為什么安全:

服務端申請CA機構頒發的證書,則獲取到了證書的公鑰和私鑰,私鑰只有服務器端自己知道,而公鑰可以告知其他人,如可以把公鑰傳給客戶端,這樣客戶端通過服務端傳來的公鑰來加密自己傳輸的數據,而服務端利用私鑰就可以解密這個數據了。由于客戶端這個用公鑰加密的數據只有私鑰能解密,而這個私鑰只有服務端有,所以數據傳輸就安全了。

上面只是簡單說了一下非對稱加密算法是如何保證數據安全的,實際上Https的工作過程遠比這要復雜(篇幅限制這里就不細說了,網上有很多相關文章):

一個是客戶端還需要驗證服務端傳來的CA證書的合法性、有效性,因為存在傳輸過程CA證書被人調包的風險,涉及到客戶端如何驗證服務器證書的合法性的問題,保證通信雙方的身份合法;

另一個是非對稱算法雖然保證了數據的安全,但是效率相對于對稱算法來說比較差,如何來優化,實現既保證了數據的安全,又提高了效率。

2)客戶端如何驗證證書的合法性:

首先CA證書一般包括以下內容:

  • 證書的頒發機構以及版本;
  • 證書的使用者;
  • 證書的公鑰;
  • 證書有效時間;
  • 證書的數字簽名Hash值以及簽名Hash算法(這個數字簽名Hash值是用證書的私鑰加密過的值);
  • 等等。

客戶端驗證服務端傳過來的證書的合法性是通過:先利用獲取到的公鑰來解密證書中的數字簽名Hash值1(因為它是利用私鑰加密的嘛),然后在利用證書里的簽名Hash算法生成一個Hash值2,如果兩個值相等,則表示證書合法,服務器端可以被信任。

3)Android開發中遇到的問題及解決:

順便說一個在項目開發中使用Android WebView加載公司測試服務器上網頁證書過期導致網頁加載不出來白屏的問題。

解決方案就是測試環境下暫時忽略SSL的報錯,這樣就可以把網頁加載出來,當然在生產上不要這么做,一個是會有安全問題,一個是google play應該審核也不會通過。

最佳辦法是重寫WebViewClient的onReceivedSslError():

  1. @Override  
  2. publicvoidonReceivedSslError(WebView view, SslErrorHandler handler, SslError error) {  
  3. if(ContextHolder.sDebug) {  
  4. handler.proceed();  
  5. return 
  6.  
  7. super.onReceivedSslError(view, handler, error);  

4.6 Http 2.0

Okhttp支持配置使用Http 2.0協議,Http2.0相對于Http1.x來說提升是巨大的,主要有以下幾點。

1)二進制格式:http1.x是文本協議,而http2.0是二進制以幀為基本單位,是一個二進制協議,一幀中除了包含數據外同時還包含該幀的標識:Stream Identifier,即標識了該幀屬于哪個request,使得網絡傳輸變得十分靈活;

2)多路復用:一個很大的改進,原先http1.x一個連接一個請求的情況有比較大的局限性,也引發了很多問題,如建立多個連接的消耗以及效率問題。

http1.x為了解決效率問題,可能會盡量多的發起并發的請求去加載資源,然而瀏覽器對于同一域名下的并發請求有限制,而優化的手段一般是將請求的資源放到不同的域名下來突破這種限制。

而http2.0支持的多路復用可以很好的解決這個問題,多個請求共用一個TCP連接,多個請求可以同時在這個TCP連接上并發,一個是解決了建立多個TCP連接的消耗問題,一個也解決了效率的問題。

那么是什么原理支撐多個請求可以在一個TCP連接上并發呢?基本原理就是上面的二進制分幀,因為每一幀都有一個身份標識,所以多個請求的不同幀可以并發的無序發送出去,在服務端會根據每一幀的身份標識,將其整理到對應的request中。

3)header頭部壓縮:主要是通過壓縮header來減少請求的大小,減少流量消耗,提高效率。因為之前存在一個問題是,每次請求都要帶上header,而這個header中的數據通常是一層不變的。

4)支持服務端推送。

5、TCP相關

TCP面向連接,提供可靠的數據傳輸。在這一層,我們通常都是通過Socket Api來操作TCP,建立連接等等。

5.1 三次握手建立連接 

  • 第一次:發送SNY=1表示此次握手是請求建立連接的,然后seq生成一個客戶端的隨機數X
  • 第二次:發送SNY=1,ACK=1表示是回復請求建立連接的,然后ack=客戶端的seq+1(這樣客戶端收到后就能確認是之前想要連接的那個服務端),然后把服務端也生成一個代表自己的隨機數seq=Y發給客戶端。
  • 第三次:ACK=1。 seq=客戶端隨機數+1,ack=服務端隨機數+1(這樣服務端就知道是剛剛那個客戶端了)

為什么建立連接需要三次握手?

首先非常明確的是兩次握手是最基本的,第一次握手,C端發了個連接請求消息到S端,S端收到后S端就知道自己與C端是可以連接成功的,但是C端此時并不知道S端是否接收到這個消息,所以S端接收到消息后得應答,C端得到S端的回復后,才能確定自己與S端是可以連接上的,這就是第二次握手。

C端只有確定了自己能與S端連接上才能開始發數據。所以兩次握手肯定是最基本的。

那么為什么需要第三次握手呢?假設一下如果沒有第三次握手,而是兩次握手后我們就認為連接建立,那么會發生什么?

第三次握手是為了防止已經失效的連接請求報文段突然又傳到服務端,因而產生錯誤。

具體情況就是:

C端發出去的第一個網絡連接請求由于某些原因在網絡節點中滯留了,導致延遲,直到連接釋放的某個時間點才到達S端,這是一個早已失效的報文,但是此時S端仍然認為這是C端的建立連接請求第一次握手,于是S端回應了C端,第二次握手。

如果只有兩次握手,那么到這里,連接就建立了,但是此時C端并沒有任何數據要發送,而S端就會傻傻的等待著,造成很大的資源浪費。所以需要第三次握手,只有C端再次回應一下,就可以避免這種情況。

5.2 四次揮手斷開連接 

經過上面的建立連接圖的解析,這個圖應該不難看懂。

這里主要有一個問題:為什么比建立連接時多了一次揮手?

可以看到這里服務端的ACK(回復客戶端)和FIN(終止)消息并不是同時發出的,而是先ACK,然后再FIN,這也很好理解,當客戶端要求斷開連接時,此時服務端可能還有未發送完的數據,所以先ACK,然后等數據發送完再FIN。這樣就變成了四次握手了。

上面講了TCP建立連接和斷開連接的過程,TCP最主要的特點就是提供可靠的傳輸,那么他是如何保證數據傳輸是可靠的呢,這就是下面要講的滑動窗口協議。

5.3 滑動窗口協議

滑動窗口協議是保證TCP的可靠傳輸的根本,因為發送窗口只有收到確認幀才會向后移動窗口繼續發送其他幀。

下面舉個例子:假如發送窗口是3幀

邁向高階:優秀Android程序員必知必會的網絡基礎

一開始發送窗口在前3幀[1,2,3],則前3幀是可以發送的,后面的則暫時不可以發送,比如[1]幀發送出去后,收到了來自接收方的確認消息,則此時發送窗口才可以往后移1幀,發送窗口來到[2,3,4],同樣只有發送窗口內的幀才可以被發送,一次類推。

而接收窗口接收到幀后將其放入對應的位置,然后移動接收窗口,接口窗口與發送窗口一樣也有一個大小,如接收窗口是5幀,則落在接收窗口之外的幀會被丟棄。

發送窗口和接收窗口大小的不同設定就延伸出了不同的協議: 

邁向高階:優秀Android程序員必知必會的網絡基礎

停止-等待協議:每發一幀都要等到確認消息才能發送下一幀,缺點:效率較差。

后退N幀協議:采取累計確認的方式,接收方正確的接受到N幀后發一個累計確認消息給發送窗口,確認N幀已正確收到,如果發送方規定時間內未收到確認消息則認為超時或數據丟失,則會重新發送確認幀之后的所有幀。缺點:出錯序號后面的PDU已經發送過了,但是還是要重新發送,比較浪費。

選擇重傳協議:若出現差錯,只重新傳輸出現差錯涉及需要的PDU,提高了傳輸效率,減少不必要的重傳。

到這里還剩下最后一個問題:由于發送窗口與接收窗口之間會存在發送效率和接收效率不匹配的問題,就會導致擁塞,解決這個問題TCP有一套流量控制和擁塞控制的機制。

5.4 流量控制和擁塞控制

1)流量控制:

流量控制是對一條通信路徑上的流量進行控制,就是發送方通過獲取接收方的回饋來動態調整發送的速率,來達到控制流量的效果,其目的是保證發送者的發送速度不超過接收者的接收速度。

2)擁塞控制:

擁塞控制是對整個通信子網的流量進行控制,屬于全局控制。

① 慢開始+擁塞避免

先來看一張經典的圖: 

一開始使用慢啟動,即擁塞窗口設為1,然后擁塞窗口指數增長到慢開始的門限值(ssthresh=16),則切換為擁塞避免,即加法增長,這樣增長到一定程度,導致網絡擁塞,則此時會把擁塞窗口重新降為1,即重新慢開始,同時調整新的慢開始門限值為12,之后以此類推。

② 快重傳+快恢復

快重傳:上面我們說的重傳機制都是等到超時還未收到接收方的回復,才開始進行重傳。而快重傳的設計思路是:如果發送方收到3個重復的接收方的ACK,就可以判斷有報文段丟失,此時就可以立即重傳丟失的報文段,而不用等到設置的超時時間到了才開始重傳,提高了重傳的效率。

快恢復:上面的擁塞控制會在網絡擁塞時將擁塞窗口降為1,重新慢開始,這樣存在的一個問題就是網絡無法很快恢復到正常狀態??旎謴途褪莵韮灮@個問題的,使用快恢復,則出現擁塞時,擁塞窗口只會降低到新的慢開始門閥值(即12),而不會降為1,然后直接開始進入擁塞避免加法增長,如下圖所示: 

快重傳和快恢復是對擁塞控制的進一步改進。

6、有關Socket

Socket是一組操作TCP/UDP的API,像HttpURLConnection和Okhttp這種涉及到比較底層的網絡請求發送的,最終當然也都是通過Socket來進行網絡請求連接發送,而像Volley、Retrofit則是更上層的封裝,最后是依靠HttpURLConnection或者Okhttp來進行最終的連接建立和請求發送。

Socket的簡單使用的話應該都會,兩個端各建立一個Socket,服務端的叫ServerSocket,然后建立連接即可。

7、本文小結

當然,以上這些內容只是我自己知道的并且認為挺重要的計算機網絡基礎,還有非常多的網絡基礎知識需要去深入了解去探索。寫了很多,算是對自己網絡基礎的一個整理,可能也會有紕漏,權當拋磚引玉,還請各位大牛不吝賜教。

責任編輯:未麗燕 來源: 簡書
相關推薦

2023-09-12 11:25:15

2019-01-30 14:14:16

LinuxUNIX操作系統

2020-05-13 11:20:57

MySQL規范數據庫

2014-02-09 10:30:17

Python程序員工具

2020-11-25 10:40:58

程序員技能開發者

2023-05-11 08:01:08

Code開發保護機制

2015-12-04 09:33:15

程序員前端演進史

2015-11-30 11:01:34

前端程序員歷史

2015-10-20 09:46:33

HTTP網絡協議

2023-10-26 18:05:37

Git命令差異

2017-08-03 14:25:13

Python陷阱與缺陷

2012-06-28 14:01:30

Java程序員排序

2020-07-10 07:58:14

Linux

2020-03-10 11:08:22

程序員美好,一直在身邊設計

2010-12-06 09:06:09

2020-03-30 15:25:14

Vim編輯器Linux

2020-10-26 15:20:05

架構運維技術

2018-07-11 14:04:53

Python陷阱缺陷

2015-05-19 14:34:17

程序員編程語言

2024-11-15 11:11:48

點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 日韩在线综合 | 亚洲午夜小视频 | 喷水毛片 | 色综合99 | 99精品九九 | 欧美xxxx日本 | 影音先锋男 | 亚洲综合精品 | 99爱视频 | 日本高清中文字幕 | 欧美激情va永久在线播放 | 欧美久久久久久 | 一级片子 | 91色视频在线 | 在线视频一区二区三区 | 成人在线免费网站 | 亚洲狠狠 | 国产精品视频久久 | 天天操网 | 91视视频在线观看入口直接观看 | 免费在线看黄视频 | 91在线免费视频 | 久久免费看 | 中文成人无字幕乱码精品 | 精品国产乱码久久久久久图片 | 国产中文字幕网 | 中文字幕精品一区二区三区精品 | 亚洲电影免费 | 欧美色综合 | 伊人一二三 | 9999国产精品欧美久久久久久 | 欧美人人| 欧美电影在线 | 黑人精品欧美一区二区蜜桃 | 国产一级特黄视频 | 国产精品视频在线免费观看 | 网站黄色在线 | 亚洲一区视频在线 | 亚洲一区在线日韩在线深爱 | 伊人青青久久 | 国产免费一区二区三区免费视频 |