Android程式設計師必知必會的網路通訊傳輸層協議——UDP和TCP
1、點評
網際網路發展至今已經高度發達,而對於網際網路應用(尤其即時通訊技術這一塊)的開發者來說,網路程式設計是基礎中的基礎,只有更好地理解相關基礎知識,對於應用層的開發才能做到遊刃有餘。
對於Android程式設計師來說,如果您覺得本文內容稍顯枯燥,可以看看即時通訊網之前整理過的一篇類似文章《邁向高階:優秀Android程式設計師必知必會的網路基礎》,該文內容更偏向於知識點的概括。
如果您希望更系統地學習網路程式設計方面的知識,可以讀一讀以下專為初學者整理的系列文章或資料:
《TCP/IP詳解 – 第11章·UDP:使用者資料包協議》
《網路程式設計懶人入門(一):快速理解網路通訊協議(上篇)》
《網路程式設計懶人入門(二):快速理解網路通訊協議(下篇)》
《網路程式設計懶人入門(四):快速理解TCP和UDP的差異》
《網路程式設計懶人入門(五):快速理解為什麼說UDP有時比TCP更有優勢》
《網路程式設計懶人入門(六):史上最通俗的集線器、交換機、路由器功能原理入門》
《網路程式設計懶人入門(七):深入淺出,全面理解HTTP協議》
《網路程式設計懶人入門(八):手把手教你寫基於TCP的Socket長連線》
《網路程式設計懶人入門(九):通俗講解,有了IP地址,為何還要用MAC地址?》
《腦殘式網路程式設計入門(一):跟著動畫來學TCP三次握手和四次揮手》
《腦殘式網路程式設計入門(二):我們在讀寫Socket時,究竟在讀寫什麼?》
《腦殘式網路程式設計入門(三):HTTP協議必知必會的一些知識》
《腦殘式網路程式設計入門(四):快速理解HTTP/2的伺服器推送(Server Push)》
學習交流:
– 即時通訊/推送技術開發交流4群:101279154[推薦]
– 移動端IM開發入門文章:《新手入門一篇就夠:從零開發移動端IM》
(本文同釋出於:http://www.52im.net/thread-2216-1-1.html)
2、前言
相信計算機專業的朋友在大學都學過《計算機網路》這門課程,但據我個人瞭解計算機專業普通大學生對計算機網路的瞭解淺之又淺,很多人說這門學科沒用,開發的時候也用不著,其實這樣想是不對的。
說一下我個人的體會,之前老是聽別人說OkHttp怎麼這麼好用,但用完之後感覺和其他框架沒多大區別啊,於是就想著去專研鑽研,當時差不多花了一個星期左右把OkHttp原始碼看了一遍,程式碼時看懂了,但是有些地方不知道為什麼這樣做,所以我就下決心把計算機網路重新學一遍,學完各種網路協議後再看OkHttp原始碼突然有種煥然一新的感覺。
在本篇文章裡,會為大家講述作為Android程式設計師的我,對於網路通訊傳輸層協議UDP、TCP的理解,希望能給你帶來啟發。
參考書籍:《計算機網路-謝希仁版》
參考教程:《韓立剛視訊教程》
3、關於作者
網名:zskingking,部落格地址:https://www.jianshu.com/u/274367e58472
4、UDP協議
4.1 概述
UDP的全稱是User Date Protocal,翻譯成中文是使用者資料包協議,它是一種不可靠的傳輸協議,一般情況下一個資料包(大概64K)能完成的資料通訊使用UDP協議,比如請求DNS解析IP地址使用的就是UDP協議,因為解析IP一個資料包完全足夠。還有就是文字聊天一般用的也是UDP,通常一段文字訊息一個資料包就足夠了,如果傳送失敗就再次傳送,反正就一個資料包。還有一種傳遞大量資料包使用UDP協議的場景,就是廣播,類似對講機之類的,接收方並不一定能接收到所有的資料包。所以說UDP是一種不可靠的傳輸協議。
UDP的主要特點:
1)UDP是無連線的,即傳送資料之前是不需要建立連線的;
2)UDP使用盡最大努力交付,不保證可靠交付,同時不使用阻塞控制;
3)UDP是面向報文的,UDP沒有擁塞控制,很適合多媒體通訊的要求;
4)UDP支援一對一、一對多、多對一、多對多的互動通訊;
5)UDP的首部開銷小,只需要8個位元組。
4.2 UDP首部
首先我們先用一張圖來表示UDP的首部,UDP首部如下圖:
UDP首部總共是8個位元組,其中源埠、目的埠、長度、檢驗和各佔2位元組。有的同學可能要問了,你怎麼沒把偽首部加進去呢?這個我來講一下,偽首部顧名思義,就是假的首部,它是不會跟隨UDP資料包進行傳輸的,它存在的意義就是為了計算UDP首部中的檢驗和。
UDP首部儲存的資訊:
1)源埠:即傳送方的埠號,需要接收方回應時選用,不需要全為0;
2)目的埠:接收方埠號;
3)長度:UDP資料包長度,最小為0(只存在首部);
4)檢驗和: 檢驗UDP資料包在傳輸中是否出錯,是就丟棄。
UDP首部組裝完畢後會將完整的資料包傳送到網路層,跟IP資料包首部組成IP資料包再向上傳送。
5、TCP協議
5.1 概述
TCP全稱為Transmission Control Protocol(傳輸控制協議),是一種可靠的面向連線傳輸協議,同時它也是一種client-server模式的協議,因為是可靠的傳輸協議,所以它比UDP要複雜的多。
首先說一下TCP具有的一些特性:
1)TCP是面向連線的傳輸協議;
2)每一條TCP有且只有兩個端點,為一對一關係;
3)TCP提供可靠互動的服務;
4)TCP提供全雙工通訊,全雙工為即可傳輸又可接收;
5)TCP是面向位元組流的。
TCP的應用場景:
如果兩個臺主機想要在網路上傳遞一部1G大小的電影,需要通過什麼協議進行傳輸呢?UDP為不可靠傳輸協議,傳遞過程中可能會出現丟包,所以UDP不行,而傳輸層就兩個協議,一個是UDP一個是TCP,UDP傳輸效率高但不可靠,TCP傳輸效率低但它是可靠的,所以想要將傳遞的檔案完整的到達目的地可以通過TCP協議進行傳輸。
5.2 TCP連線建立與斷開
在5.1中介紹TCP特性的時候提到,TCP是面向連線的,即TCP在傳輸資料前要建立連線,資料傳輸完畢後要斷開連線。TCP連線必須要由客戶端發起。
【5.2.1】TCP建立連線過程:
如上圖2所示:客戶端向服務端發起建立連線的請求,服務端接收到請求後告訴客戶端:“我準備好了”,客戶端接收到服務端的響應再給服務端一個確認,此過程總共分為三步被大家親切的成為:“三次握手”,三次握手後一個可靠的連線就建立了,隨後就可以進行資料的傳輸了,圖中SYN、ACK這些欄位我會在TCP首部中詳細介紹,此處大家可以忽略。
疑點: TCP建立連線為什麼是三次握手?兩次握手不是已經可以建立一個連線了嗎?網路上很多文章對此處的描述大多是輕描淡寫,還有的說是必須要三次握手才能建立一個可靠連線,其實這樣說是不對的,當時我也因為這些不負責任的回答費解了很久。一般情況下,兩次握手是可以建立一個TCP連線的,在《計算機網路-謝希仁》中大概是這樣解釋的:“第三次握手是為了避免服務端造成資源的浪費”,為什麼這樣說呢?我來給大家舉一個例子:
假如TCP是兩次握手:主機A向主機B傳送了一個建立連線的請求x,但這個請求在半路里給堵了,主機A沒有得到主機B的響應於是又發了一個建立連線的請求y,主機B收到了請求y,於是給主機A傳送了一個確認,此時連線建立,資料傳輸完畢後斷開了連線,但在斷開連線後堵在半路的請求x到達了主機B,此時主機B認為主機A又給自己傳送了一個建立連線的請求,於是給主機A傳送了一個確認,此時主機B認為連線已經建立,處於等待狀態從而導致主機B資源的浪費。但如果是三次握手就可以避免這種情況的出現,所以這才是TCP第三次握手的原因。
【5.2.2】TCP斷開連線過程:
如上圖所示:主機A至主機B資料傳輸結束後主機A會向主機B傳送一個斷開連線請求,主機B收到後給主機A一個確認,A就不可向B傳輸資料了,但此時主機B仍然可以往主機A傳輸資料,等B->A資料傳輸結束後主機B向主機A傳送一個斷開連線請求。主機A收到後給予一個確認,這樣就成功斷開一個TCP連線,過程分四步,也被大家親切的稱為:“四次揮手”。
疑點:斷開連線為什麼是四次揮手?兩次不就可以了嗎?下面我來用一個形象的例子來個大家解除疑點
TCP是全雙工的:即client和server都可以進行傳輸和接收,假設主機A和主機B建立了一個TCP連線,主機A可以往主機B傳送資料同時主機B也可以往主機A傳送資料,現在我將主機A->主機B描述成一根水管x,水管x只能由A流到B,主機B->主機A為水管y,水管y只能由B流到A,現在水管x已經完成的它的輸送水源工作,此時就可以將水管x切除,對應圖中前兩次揮手,但此時水管y還在工作,必須要等水管y工作完成後才能夠將其切除,切除水管y對應圖中後兩次揮手。
5.3 TCP首部
首先用一張圖來表示TCP首部的構造,TCP首部如下圖所示:
TCP首部的各項內容解釋:
1)源埠:傳送方埠號;
2)目的埠:接收方埠;
3)序號:資料包的序號,以資料包第一個位元組進行表示;
4)確認號:確認收到資料包的序號,同樣以位元組進行標識;
5)資料偏移:TCP首部長度,以位元組為單位;
6)保留:保留位,總共6為,必須都為0;
7)URG:緊急處理,可提升資料包傳送的優先順序;
8)ACK:代表確認號是否有效;
9)RST:將建立的連線重置;
10)PSH:接收方應儘快將這個報文交給應用層;
11)SYN:同步序號用來發起一個連線;
12)FIN:終止一個連線。
本小節只是讓大家對TCP首部有一個概念性的認識,所以你可能會對首部中某些欄位不太理解,沒關係,在下面的文章中我還會提到這些欄位。
5.4 TCP進行可靠傳輸
我們知道網路傳輸是不可靠的,可能存在丟包的現象,TCP是可靠的傳輸協議,那麼它是怎麼做到可靠傳輸呢?我來用幾張圖為大家分析TCP師怎樣進行可靠傳輸的。
如下圖所示:
情況a:A傳送給B資料包M1,B收到之後進行確認,這樣M1包就傳送成功了,以此類推,這是無差錯的情況。
情況b:A傳送資料包M1給B,但中途被丟棄了,如果A遲遲等不到B的響應那麼A就會重新傳送M1包給B。
如下圖所示:
情況a:A傳送資料包M1給B,B收到後給A傳送一個M1的確認包但該確認包在中途被丟棄了,A遲遲未收到B的確認包就認為M1傳送包或者M1確認包早中途丟失了,於是又傳送了一個M1包給B,B又收到了一個M1包,此時B就可以認為M1確認包可能在中途丟失了,將重複的M1包丟棄後再給A傳送一個M1確認包;
情況b:A傳送資料包M1給B,B收到後給A傳送一個M1確認包,但該確認包選擇了一個較遠的傳輸路線或者被阻塞了,A遲遲未收到M1確認包就再給B傳送一個M1包,B收到重複的M1包後將其丟棄然後再給A傳送一個M1確認包,A收到M1確認後就認為M1傳送成功,但此時A收到半路阻塞的那個M1確認包,而A已經確認了M1包傳送成功,所以再次受到M1確認包後什麼也不做。
client-server可以通過傳遞確認的方式來實現可靠傳輸,但這種傳輸方式有一個缺點,效率太低,因為在未收到確認包前是不可以傳送下一個包的,那麼我們能不能突破這一限制來提升傳輸效率呢?我們可以通過提升通道的利用率來提升傳輸效率,如下圖所示:
從上圖我們可以看到,A在未收到B確認前傳送了10個資料包,在這我就將10個資料包形象的編號為1-10,A一次傳送10個資料包,當B收到資料包1的時候給A一個確認,A收到確認後再傳送資料包11,當B收到資料包2的時候給A一個確認,A收到確認後再傳送資料包12,以此類推。
上圖中A最多一次可以連續傳送10個資料包,而這個10我們可不可以理解為一個視窗呢?打個比方,現在有一個視窗共有10個格子,每個格子放一個資料包,傳送的資料包放在格子裡面,當收到第一個資料包的確認包後將該資料包從視窗中移出,然後將需要傳送的下一個資料包放入視窗。
我們這裡提到的視窗就是TCP首部裡面說的那個視窗,下面我結合圖給大家分析一遍:
上圖中,現在我們有12個資料包需要傳送,視窗大小為5,所以最多一次可連續傳送5個資料包,假設現在視窗中的五個資料包都已經傳送完畢,此時收到了資料包1的確認包,那麼綠色視窗就可以往右邊移一個格子,如下圖:
上圖中,資料包6被滑進格子裡,此時資料包6就可以被髮送,同時資料包1也可以從快取中清除,通過這種方式可以提升通道的利用率從而提升傳輸效率,但這種傳輸方式也有一個缺點,就是接收方每收到一個資料包都要進行一次確認,這是完全沒必要的,我們可不可以這樣做:每收到5個資料包進行一個確認,如下圖:
A一次給B傳送了5個資料包,B確認5個資料包都收到了,給A回覆一個6,代表B已經收到了前5個資料包讓A下次從第6個資料包開始傳送,通過累積響應這種方式又進一步提升了傳輸效率,但這是理想情況下,如果說A傳送完5個資料包,B只收到了1、2、4、5,資料包3丟了,怎麼辦?是直接給A回覆一個3嗎?是的話4、5都要進行重傳,這樣就得不償失了,而編寫TCP協議那位老哥也想到了這種情況,所以就指定了相應的策略,接著剛剛說,如果B確定資料包3丟了或者被阻塞了,那麼它會立刻連續傳送3個3,A收到連續的3個3後就認為資料包3丟了,然後就會只補傳資料包3。
注意點:
上面的內容中我為了方便講解都是把資料包編成編號進行描述,其實真正的資料包編號不是這樣的,TCP協議是面向位元組流的,所以說序號和確認號應以位元組為標準,比如:A現在向B傳送了5和資料包共100個位元組,B收到這5個資料包後會給A回覆一個101,此時A就會從第101個位元組開始進行傳送,以此類推。同時通過這種機制也可以實現斷點的下載。
5.5 流量控制
流量控制:用來協調server和client兩端因處理資料速度不同所帶來的問題。
舉個例子:
假如主機A要向主機B傳送資料,如果主機A傳送資料的速度比主機B處理資料的速度要快,那麼很可能導致主機B崩潰,通過TCP流量控制技術可以調整主機A傳送資料的速度從而解決上面的問題。
TCP是怎樣實現流量控制的的?首先說明一點,前面我們描述TCP傳輸資料的時候提到了滑動視窗這個概念,其實不光傳送方存在滑動視窗,同樣接收方也存在滑動視窗,接收方收到資料包後會將資料包放入滑動視窗,對資料包操作完畢後將該資料包從滑動視窗中移出,當滑動視窗被填滿時不可以再接收資料,TCP中傳送發視窗和接收方視窗大小是相同的。
所以,通過滑動視窗機制可以實現流量控制,如下圖所示:
上圖中,B為傳送方A為接收方,當B與A建立連線的時候首先會明確自己滑動視窗的大小,假如是10,B就會將rwnd(滑動視窗)設定為10,A收到後也會將滑動視窗設定為10,連線建立成功會A開始向B傳送資料,我們知道滑動視窗越大傳送的速度越快,假如rwnd=10時B處理資料包的速度小於接收資料包的速度那麼滑動視窗會逐漸被填滿,這樣會導致主機B中未處理的資料包越來越多最終可能會崩潰,為了避免這種情況的出現,B可以在滑動視窗被填滿了之後給A傳送一個rwnd=6,A接收到rwnd=6後會將滑動視窗調整為6進而降低傳送資料的速度,同樣B如果覺得A的傳送速度過慢也可以通過設定rwnd的值來調整A的傳送速度,B動態的設定A的滑動視窗就稱作為TCP流量控制技術。
5.6 擁塞避免
什麼是擁塞呢?顧名思義就是賭了,資料被堵在半路了,那什麼情況下會出現資料被堵在半路呢?
舉個例子:
假如現有兩臺主機分別是傳送方主機A和接收方主機B,主機B的頻寬為50M/S,也就是說主機B每秒最多能接收50M的資料,如果主機A的傳送速度遠低於50M/S,這種情況應該是不會出現擁塞現象的,但是如果主機A的傳送速度遠大於50M/S,主機B的路由器接手不了這麼多資料只能進行丟棄,路由器也是有CPU、記憶體和自己的作業系統,當主句A傳送速度越快主機B的路由器CPU和記憶體就要分配更多的資源去處理丟棄資料包,這樣就會導致接收資料包的速度越來越低,極端的情況下可能會出現主機B接收不到資料包的現象,也就是死鎖現象。
如果在進行TCP資料傳輸的時候不進行流量控制很容易出現死鎖現象,因為網路是大家共用的,所以避免網路擁塞現象的出現需要所有計算機遵守一種特定的規則,那這種規則是怎樣控制網路避免擁塞的呢?
先來看下面這張圖:
如果不進行擁塞控制就是我們上面所說的,最終可能會出現上圖中綠線的情況,現在我們要通過擁塞控制使網路資料傳輸按照上圖中藍線進行。
下面我們來說一下如何進行擁塞控制:
首先將滑動視窗設定為1,然後再傳輸過程中逐漸以指數倍增加,當滑動視窗到達ssthresh的時候再以加法進行增加,如果出現了擁塞現象就迅速再將滑動視窗設定為1,ssthresh減小依次迴圈,這種方式也稱為慢開始方式。但這種方式已經被廢棄,因為每次出現擁塞的時候都會將滑動視窗設定為0再進行慢開始階段,這樣其實是完全沒必要的。
我們再來看升級版,如下圖:
在出現擁塞的時候並不會將滑動視窗設定為1重新進行慢開始,而是將滑動視窗設定為出現擁塞時視窗的一半,然後再以加法進行增加,此過程也可稱為是快恢復,這樣就可以避免網路擁塞的出現。
附錄:更多網路程式設計文章
《技術往事:改變世界的TCP/IP協議(珍貴多圖、手機慎點)》
《通俗易懂-深入理解TCP協議(下):RTT、滑動視窗、擁塞處理》
《理論聯絡實際:Wireshark抓包分析TCP 3次握手、4次揮手過程》
《P2P技術詳解(一):NAT詳解——詳細原理、P2P簡介》
《P2P技術詳解(二):P2P中的NAT穿越(打洞)方案詳解》
《P2P技術詳解(三):P2P技術之STUN、TURN、ICE詳解》
《高效能網路程式設計(一):單臺伺服器併發TCP連線數到底可以有多少》
《高效能網路程式設計(二):上一個10年,著名的C10K併發連線問題》
《高效能網路程式設計(三):下一個10年,是時候考慮C10M併發問題了》
《高效能網路程式設計(四):從C10K到C10M高效能網路應用的理論探索》
《高效能網路程式設計(五):一文讀懂高效能網路程式設計中的I/O模型》
《高效能網路程式設計(六):一文讀懂高效能網路程式設計中的執行緒模型》
《不為人知的網路程式設計(一):淺析TCP協議中的疑難雜症(上篇)》
《不為人知的網路程式設計(二):淺析TCP協議中的疑難雜症(下篇)》
《不為人知的網路程式設計(三):關閉TCP連線時為什麼會TIME_WAIT、CLOSE_WAIT》
《不為人知的網路程式設計(四):深入研究分析TCP的異常關閉》
《不為人知的網路程式設計(六):深入地理解UDP協議並用好它》
《不為人知的網路程式設計(七):如何讓不可靠的UDP變的可靠?》
《技術掃盲:新一代基於UDP的低延時網路傳輸層協議——QUIC詳解》
《現代移動端網路短連線的優化手段總結:請求速度、弱網適應、安全保障》
《移動端IM開發者必讀(一):通俗易懂,理解行動網路的“弱”和“慢”》
《移動端IM開發者必讀(二):史上最全移動弱網路優化方法總結》
《從HTTP/0.9到HTTP/2:一文讀懂HTTP協議的歷史演變和設計思路》
《以網遊服務端的網路接入層設計為例,理解實時通訊的技術挑戰》
《邁向高階:優秀Android程式設計師必知必會的網路基礎》
《全面瞭解移動端DNS域名劫持等雜症:技術原理、問題根源、解決方案等》
《美圖App的移動端DNS優化實踐:HTTPS請求耗時減小近半》
《Android程式設計師必知必會的網路通訊傳輸層協議——UDP和TCP》
>> 更多同類文章 ……
(本文同釋出於:http://www.52im.net/thread-2216-1-1.html)
相關文章
- 傳輸層協議 TCP 和 UDP協議TCPUDP
- Python 網路資料傳輸協議 TCP 程式設計Python協議TCP程式設計
- Python 基於 TCP 傳輸協議的網路通訊實現PythonTCP協議
- Android與物聯網裝置通訊-UDP&TCP協議AndroidUDPTCP協議
- TCP/IP五層模型-傳輸層-TCP協議TCP模型協議
- 好程式設計師Python培訓分享udp和tcp協議介紹程式設計師PythonUDPTCP協議
- UDP協議網路Socket程式設計(java實現C/S通訊案例)UDP協議程式設計Java
- 網路通訊協議-TCP協議詳解!協議TCP
- 資料通訊與網路 第五版第24章 傳輸層協議-TCP協議部分要點協議TCP
- TCP和UDP協議TCPUDP協議
- 網路程式設計協議(TCP和UDP協議,黏包問題)以及socketserver模組程式設計協議TCPUDPServer
- 網路協議之:基於UDP的高速資料傳輸協議UDT協議UDP
- TCP/IP協議 - 網路層TCP協議
- Java:基於TCP協議網路socket程式設計(實現C/S通訊)JavaTCP協議程式設計
- Java&Python的TCP&UDP通訊-網路程式設計JavaPythonTCPUDP程式設計
- 基於TCP/UDP的Socket程式設計,HTTP/HTTPS協議TCPUDP程式設計HTTP協議
- 計算機網路之八:TCP協議(2) TCP可靠傳輸的實現計算機網路TCP協議
- 網路程式設計UDP協議方式程式設計UDP協議
- IT程式設計師必知!TCP/IP為什麼會有這麼多的致命漏洞?程式設計師TCP
- TCP 和 UDP 協議簡介TCPUDP協議
- 傳輸控制協議/網際網路協議(TCP / IP)是什麼意思?-VeCloud協議TCPCloud
- Java 網路程式設計(TCP程式設計 和 UDP程式設計)Java程式設計TCPUDP
- 傳輸層協議協議
- 前端必須懂的計算機網路知識—(TCP)前端計算機網路TCP
- 那些 Android 程式設計師必會的檢視優化策略Android程式設計師優化
- 【網路程式設計】Tcp/Udp程式設計TCPUDP
- Docker 必知必會4----容器之間的通訊Docker
- Java 多執行緒與併發程式設計 · Java 工程師必知必會Java執行緒程式設計工程師
- 《Linux網路開發必學教程》12_TCP通訊框架:服務端設計LinuxTCP框架服務端
- 《Linux網路開發必學教程》7_TCP 與 UDPLinuxTCPUDP
- 一網打盡:Java 程式設計師必須瞭解的計算機底層知識!Java程式設計師計算機
- 如何設計一個好的通訊網路協議協議
- TCP傳輸協議詳解TCP協議
- Linux 程式必知必會Linux
- 學會Zynq(11)RAW API的TCP和UDP程式設計APITCPUDP程式設計
- 通過故事引申網路協議TCP協議TCP
- 淺談TCP和UDP協議的區別TCPUDP協議
- TCP/IP 協議及網路分層模型TCP協議模型