1、點(diǎn)評(píng)
互聯(lián)網(wǎng)發(fā)展至今已經(jīng)高度發(fā)達(dá),而對(duì)于互聯(lián)網(wǎng)應(yīng)用(尤其即時(shí)通訊技術(shù)這一塊)的開發(fā)者來說,網(wǎng)絡(luò)編程是基礎(chǔ)中的基礎(chǔ),只有更好地理解相關(guān)基礎(chǔ)知識(shí),對(duì)于應(yīng)用層的開發(fā)才能做到游刃有余。
對(duì)于Android程序員來說,如果您覺得本文內(nèi)容稍顯枯燥,可以看看即時(shí)通訊網(wǎng)之前整理過的一篇類似文章《邁向高階:優(yōu)秀Android程序員必知必會(huì)的網(wǎng)絡(luò)基礎(chǔ)》,該文內(nèi)容更偏向于知識(shí)點(diǎn)的概括。
如果您希望更系統(tǒng)地學(xué)習(xí)網(wǎng)絡(luò)編程方面的知識(shí),可以讀一讀以下專為初學(xué)者整理的系列文章或資料:
《TCP/IP詳解 - 第11章·UDP:用戶數(shù)據(jù)報(bào)協(xié)議》
《TCP/IP詳解 - 第17章·TCP:傳輸控制協(xié)議》
《TCP/IP詳解 - 第18章·TCP連接的建立與終止》
《TCP/IP詳解 - 第21章·TCP的超時(shí)與重傳》
《網(wǎng)絡(luò)編程懶人入門(一):快速理解網(wǎng)絡(luò)通信協(xié)議(上篇)》
《網(wǎng)絡(luò)編程懶人入門(二):快速理解網(wǎng)絡(luò)通信協(xié)議(下篇)》
《網(wǎng)絡(luò)編程懶人入門(三):快速理解TCP協(xié)議一篇就夠》
《網(wǎng)絡(luò)編程懶人入門(四):快速理解TCP和UDP的差異》
《網(wǎng)絡(luò)編程懶人入門(五):快速理解為什么說UDP有時(shí)比TCP更有優(yōu)勢》
《網(wǎng)絡(luò)編程懶人入門(六):史上最通俗的集線器、交換機(jī)、路由器功能原理入門》
《網(wǎng)絡(luò)編程懶人入門(七):深入淺出,全面理解HTTP協(xié)議》
《網(wǎng)絡(luò)編程懶人入門(八):手把手教你寫基于TCP的Socket長連接》
《網(wǎng)絡(luò)編程懶人入門(九):通俗講解,有了IP地址,為何還要用MAC地址?》
《腦殘式網(wǎng)絡(luò)編程入門(一):跟著動(dòng)畫來學(xué)TCP三次握手和四次揮手》
《腦殘式網(wǎng)絡(luò)編程入門(二):我們在讀寫Socket時(shí),究竟在讀寫什么?》
《腦殘式網(wǎng)絡(luò)編程入門(三):HTTP協(xié)議必知必會(huì)的一些知識(shí)》
《腦殘式網(wǎng)絡(luò)編程入門(四):快速理解HTTP/2的服務(wù)器推送(Server Push)》
《腦殘式網(wǎng)絡(luò)編程入門(五):每天都在用的Ping命令,它到底是什么?》
《腦殘式網(wǎng)絡(luò)編程入門(六):什么是公網(wǎng)IP和內(nèi)網(wǎng)IP?NAT轉(zhuǎn)換又是什么鬼?》
學(xué)習(xí)交流:
- 即時(shí)通訊/推送技術(shù)開發(fā)交流4群:101279154[推薦]
- 移動(dòng)端IM開發(fā)入門文章:《新手入門一篇就夠:從零開發(fā)移動(dòng)端IM》
(本文同發(fā)布于:http://www.52im.net/thread-2216-1-1.html)
2、前言
相信計(jì)算機(jī)專業(yè)的朋友在大學(xué)都學(xué)過《計(jì)算機(jī)網(wǎng)絡(luò)》這門課程,但據(jù)我個(gè)人了解計(jì)算機(jī)專業(yè)普通大學(xué)生對(duì)計(jì)算機(jī)網(wǎng)絡(luò)的了解淺之又淺,很多人說這門學(xué)科沒用,開發(fā)的時(shí)候也用不著,其實(shí)這樣想是不對(duì)的。
說一下我個(gè)人的體會(huì),之前老是聽別人說OkHttp怎么這么好用,但用完之后感覺和其他框架沒多大區(qū)別啊,于是就想著去專研鉆研,當(dāng)時(shí)差不多花了一個(gè)星期左右把OkHttp源碼看了一遍,代碼時(shí)看懂了,但是有些地方不知道為什么這樣做,所以我就下決心把計(jì)算機(jī)網(wǎng)絡(luò)重新學(xué)一遍,學(xué)完各種網(wǎng)絡(luò)協(xié)議后再看OkHttp源碼突然有種煥然一新的感覺。
在本篇文章里,會(huì)為大家講述作為Android程序員的我,對(duì)于網(wǎng)絡(luò)通信傳輸層協(xié)議UDP、TCP的理解,希望能給你帶來啟發(fā)。
參考書籍:《計(jì)算機(jī)網(wǎng)絡(luò)-謝希仁版》
參考教程:《韓立剛視頻教程》
3、關(guān)于作者
網(wǎng)名:zskingking,博客地址:https://www.jianshu.com/u/274367e58472
4、UDP協(xié)議
4.1 概述
UDP的全稱是User Date Protocal,翻譯成中文是用戶數(shù)據(jù)包協(xié)議,它是一種不可靠的傳輸協(xié)議,一般情況下一個(gè)數(shù)據(jù)包(大概64K)能完成的數(shù)據(jù)通訊使用UDP協(xié)議,比如請(qǐng)求DNS解析IP地址使用的就是UDP協(xié)議,因?yàn)榻馕鯥P一個(gè)數(shù)據(jù)包完全足夠。還有就是文字聊天一般用的也是UDP,通常一段文字消息一個(gè)數(shù)據(jù)包就足夠了,如果發(fā)送失敗就再次發(fā)送,反正就一個(gè)數(shù)據(jù)包。還有一種傳遞大量數(shù)據(jù)包使用UDP協(xié)議的場景,就是廣播,類似對(duì)講機(jī)之類的,接收方并不一定能接收到所有的數(shù)據(jù)包。所以說UDP是一種不可靠的傳輸協(xié)議。
UDP的主要特點(diǎn):
1)UDP是無連接的,即發(fā)送數(shù)據(jù)之前是不需要建立連接的;
2)UDP使用盡最大努力交付,不保證可靠交付,同時(shí)不使用阻塞控制;
3)UDP是面向報(bào)文的,UDP沒有擁塞控制,很適合多媒體通信的要求;
4)UDP支持一對(duì)一、一對(duì)多、多對(duì)一、多對(duì)多的交互通信;
5)UDP的首部開銷小,只需要8個(gè)字節(jié)。
4.2 UDP首部
首先我們先用一張圖來表示UDP的首部,UDP首部如下圖:
UDP首部總共是8個(gè)字節(jié),其中源端口、目的端口、長度、檢驗(yàn)和各占2字節(jié)。有的同學(xué)可能要問了,你怎么沒把偽首部加進(jìn)去呢?這個(gè)我來講一下,偽首部顧名思義,就是假的首部,它是不會(huì)跟隨UDP數(shù)據(jù)報(bào)進(jìn)行傳輸?shù)模嬖诘囊饬x就是為了計(jì)算UDP首部中的檢驗(yàn)和。
UDP首部存儲(chǔ)的信息:
1)源端口:即發(fā)送方的端口號(hào),需要接收方回應(yīng)時(shí)選用,不需要全為0;
2)目的端口:接收方端口號(hào);
3)長度:UDP數(shù)據(jù)報(bào)長度,最小為0(只存在首部);
4)檢驗(yàn)和: 檢驗(yàn)UDP數(shù)據(jù)報(bào)在傳輸中是否出錯(cuò),是就丟棄。
UDP首部組裝完畢后會(huì)將完整的數(shù)據(jù)報(bào)發(fā)送到網(wǎng)絡(luò)層,跟IP數(shù)據(jù)報(bào)首部組成IP數(shù)據(jù)報(bào)再向上發(fā)送。
5、TCP協(xié)議
5.1 概述
TCP全稱為Transmission Control Protocol(傳輸控制協(xié)議),是一種可靠的面向連接傳輸協(xié)議,同時(shí)它也是一種client-server模式的協(xié)議,因?yàn)槭强煽康膫鬏攨f(xié)議,所以它比UDP要復(fù)雜的多。
首先說一下TCP具有的一些特性:
1)TCP是面向連接的傳輸協(xié)議;
2)每一條TCP有且只有兩個(gè)端點(diǎn),為一對(duì)一關(guān)系;
3)TCP提供可靠交互的服務(wù);
4)TCP提供全雙工通信,全雙工為即可傳輸又可接收;
5)TCP是面向字節(jié)流的。
TCP的應(yīng)用場景:
如果兩個(gè)臺(tái)主機(jī)想要在網(wǎng)絡(luò)上傳遞一部1G大小的電影,需要通過什么協(xié)議進(jìn)行傳輸呢?UDP為不可靠傳輸協(xié)議,傳遞過程中可能會(huì)出現(xiàn)丟包,所以UDP不行,而傳輸層就兩個(gè)協(xié)議,一個(gè)是UDP一個(gè)是TCP,UDP傳輸效率高但不可靠,TCP傳輸效率低但它是可靠的,所以想要將傳遞的文件完整的到達(dá)目的地可以通過TCP協(xié)議進(jìn)行傳輸。
5.2 TCP連接建立與斷開
在5.1中介紹TCP特性的時(shí)候提到,TCP是面向連接的,即TCP在傳輸數(shù)據(jù)前要建立連接,數(shù)據(jù)傳輸完畢后要斷開連接。TCP連接必須要由客戶端發(fā)起。
【5.2.1】TCP建立連接過程:
如上圖2所示:客戶端向服務(wù)端發(fā)起建立連接的請(qǐng)求,服務(wù)端接收到請(qǐng)求后告訴客戶端:“我準(zhǔn)備好了”,客戶端接收到服務(wù)端的響應(yīng)再給服務(wù)端一個(gè)確認(rèn),此過程總共分為三步被大家親切的成為:“三次握手”,三次握手后一個(gè)可靠的連接就建立了,隨后就可以進(jìn)行數(shù)據(jù)的傳輸了,圖中SYN、ACK這些字段我會(huì)在TCP首部中詳細(xì)介紹,此處大家可以忽略。
疑點(diǎn): TCP建立連接為什么是三次握手?兩次握手不是已經(jīng)可以建立一個(gè)連接了嗎?網(wǎng)絡(luò)上很多文章對(duì)此處的描述大多是輕描淡寫,還有的說是必須要三次握手才能建立一個(gè)可靠連接,其實(shí)這樣說是不對(duì)的,當(dāng)時(shí)我也因?yàn)檫@些不負(fù)責(zé)任的回答費(fèi)解了很久。一般情況下,兩次握手是可以建立一個(gè)TCP連接的,在《計(jì)算機(jī)網(wǎng)絡(luò)-謝希仁》中大概是這樣解釋的:“第三次握手是為了避免服務(wù)端造成資源的浪費(fèi)”,為什么這樣說呢?我來給大家舉一個(gè)例子:
假如TCP是兩次握手:主機(jī)A向主機(jī)B發(fā)送了一個(gè)建立連接的請(qǐng)求x,但這個(gè)請(qǐng)求在半路里給堵了,主機(jī)A沒有得到主機(jī)B的響應(yīng)于是又發(fā)了一個(gè)建立連接的請(qǐng)求y,主機(jī)B收到了請(qǐng)求y,于是給主機(jī)A發(fā)送了一個(gè)確認(rèn),此時(shí)連接建立,數(shù)據(jù)傳輸完畢后斷開了連接,但在斷開連接后堵在半路的請(qǐng)求x到達(dá)了主機(jī)B,此時(shí)主機(jī)B認(rèn)為主機(jī)A又給自己發(fā)送了一個(gè)建立連接的請(qǐng)求,于是給主機(jī)A發(fā)送了一個(gè)確認(rèn),此時(shí)主機(jī)B認(rèn)為連接已經(jīng)建立,處于等待狀態(tài)從而導(dǎo)致主機(jī)B資源的浪費(fèi)。但如果是三次握手就可以避免這種情況的出現(xiàn),所以這才是TCP第三次握手的原因。
【5.2.2】TCP斷開連接過程:
如上圖所示:主機(jī)A至主機(jī)B數(shù)據(jù)傳輸結(jié)束后主機(jī)A會(huì)向主機(jī)B發(fā)送一個(gè)斷開連接請(qǐng)求,主機(jī)B收到后給主機(jī)A一個(gè)確認(rèn),A就不可向B傳輸數(shù)據(jù)了,但此時(shí)主機(jī)B仍然可以往主機(jī)A傳輸數(shù)據(jù),等B->A數(shù)據(jù)傳輸結(jié)束后主機(jī)B向主機(jī)A發(fā)送一個(gè)斷開連接請(qǐng)求。主機(jī)A收到后給予一個(gè)確認(rèn),這樣就成功斷開一個(gè)TCP連接,過程分四步,也被大家親切的稱為:“四次揮手”。
疑點(diǎn):斷開連接為什么是四次揮手?兩次不就可以了嗎?下面我來用一個(gè)形象的例子來個(gè)大家解除疑點(diǎn)
TCP是全雙工的:即client和server都可以進(jìn)行傳輸和接收,假設(shè)主機(jī)A和主機(jī)B建立了一個(gè)TCP連接,主機(jī)A可以往主機(jī)B發(fā)送數(shù)據(jù)同時(shí)主機(jī)B也可以往主機(jī)A發(fā)送數(shù)據(jù),現(xiàn)在我將主機(jī)A->主機(jī)B描述成一根水管x,水管x只能由A流到B,主機(jī)B->主機(jī)A為水管y,水管y只能由B流到A,現(xiàn)在水管x已經(jīng)完成的它的輸送水源工作,此時(shí)就可以將水管x切除,對(duì)應(yīng)圖中前兩次揮手,但此時(shí)水管y還在工作,必須要等水管y工作完成后才能夠?qū)⑵淝谐谐躽對(duì)應(yīng)圖中后兩次揮手。
5.3 TCP首部
首先用一張圖來表示TCP首部的構(gòu)造,TCP首部如下圖所示:
TCP首部的各項(xiàng)內(nèi)容解釋:
1)源端口:發(fā)送方端口號(hào);
2)目的端口:接收方端口;
3)序號(hào):數(shù)據(jù)包的序號(hào),以數(shù)據(jù)包第一個(gè)字節(jié)進(jìn)行表示;
4)確認(rèn)號(hào):確認(rèn)收到數(shù)據(jù)包的序號(hào),同樣以字節(jié)進(jìn)行標(biāo)識(shí);
5)數(shù)據(jù)偏移:TCP首部長度,以字節(jié)為單位;
6)保留:保留位,總共6為,必須都為0;
7)URG:緊急處理,可提升數(shù)據(jù)包發(fā)送的優(yōu)先級(jí);
8)ACK:代表確認(rèn)號(hào)是否有效;
9)RST:將建立的連接重置;
10)PSH:接收方應(yīng)盡快將這個(gè)報(bào)文交給應(yīng)用層;
11)SYN:同步序號(hào)用來發(fā)起一個(gè)連接;
12)FIN:終止一個(gè)連接。
本小節(jié)只是讓大家對(duì)TCP首部有一個(gè)概念性的認(rèn)識(shí),所以你可能會(huì)對(duì)首部中某些字段不太理解,沒關(guān)系,在下面的文章中我還會(huì)提到這些字段。
5.4 TCP進(jìn)行可靠傳輸
我們知道網(wǎng)絡(luò)傳輸是不可靠的,可能存在丟包的現(xiàn)象,TCP是可靠的傳輸協(xié)議,那么它是怎么做到可靠傳輸呢?我來用幾張圖為大家分析TCP師怎樣進(jìn)行可靠傳輸?shù)摹?/p>
如下圖所示:
情況a:A發(fā)送給B數(shù)據(jù)包M1,B收到之后進(jìn)行確認(rèn),這樣M1包就發(fā)送成功了,以此類推,這是無差錯(cuò)的情況。
情況b:A發(fā)送數(shù)據(jù)包M1給B,但中途被丟棄了,如果A遲遲等不到B的響應(yīng)那么A就會(huì)重新發(fā)送M1包給B。
如下圖所示:
情況a:A發(fā)送數(shù)據(jù)包M1給B,B收到后給A發(fā)送一個(gè)M1的確認(rèn)包但該確認(rèn)包在中途被丟棄了,A遲遲未收到B的確認(rèn)包就認(rèn)為M1發(fā)送包或者M(jìn)1確認(rèn)包早中途丟失了,于是又發(fā)送了一個(gè)M1包給B,B又收到了一個(gè)M1包,此時(shí)B就可以認(rèn)為M1確認(rèn)包可能在中途丟失了,將重復(fù)的M1包丟棄后再給A發(fā)送一個(gè)M1確認(rèn)包;
情況b:A發(fā)送數(shù)據(jù)包M1給B,B收到后給A發(fā)送一個(gè)M1確認(rèn)包,但該確認(rèn)包選擇了一個(gè)較遠(yuǎn)的傳輸路線或者被阻塞了,A遲遲未收到M1確認(rèn)包就再給B發(fā)送一個(gè)M1包,B收到重復(fù)的M1包后將其丟棄然后再給A發(fā)送一個(gè)M1確認(rèn)包,A收到M1確認(rèn)后就認(rèn)為M1發(fā)送成功,但此時(shí)A收到半路阻塞的那個(gè)M1確認(rèn)包,而A已經(jīng)確認(rèn)了M1包發(fā)送成功,所以再次受到M1確認(rèn)包后什么也不做。
client-server可以通過傳遞確認(rèn)的方式來實(shí)現(xiàn)可靠傳輸,但這種傳輸方式有一個(gè)缺點(diǎn),效率太低,因?yàn)樵谖词盏酱_認(rèn)包前是不可以發(fā)送下一個(gè)包的,那么我們能不能突破這一限制來提升傳輸效率呢?我們可以通過提升信道的利用率來提升傳輸效率,如下圖所示:
從上圖我們可以看到,A在未收到B確認(rèn)前發(fā)送了10個(gè)數(shù)據(jù)包,在這我就將10個(gè)數(shù)據(jù)包形象的編號(hào)為1-10,A一次發(fā)送10個(gè)數(shù)據(jù)包,當(dāng)B收到數(shù)據(jù)包1的時(shí)候給A一個(gè)確認(rèn),A收到確認(rèn)后再發(fā)送數(shù)據(jù)包11,當(dāng)B收到數(shù)據(jù)包2的時(shí)候給A一個(gè)確認(rèn),A收到確認(rèn)后再發(fā)送數(shù)據(jù)包12,以此類推。
上圖中A最多一次可以連續(xù)發(fā)送10個(gè)數(shù)據(jù)包,而這個(gè)10我們可不可以理解為一個(gè)窗口呢?打個(gè)比方,現(xiàn)在有一個(gè)窗口共有10個(gè)格子,每個(gè)格子放一個(gè)數(shù)據(jù)包,發(fā)送的數(shù)據(jù)包放在格子里面,當(dāng)收到第一個(gè)數(shù)據(jù)包的確認(rèn)包后將該數(shù)據(jù)包從窗口中移出,然后將需要發(fā)送的下一個(gè)數(shù)據(jù)包放入窗口。
我們這里提到的窗口就是TCP首部里面說的那個(gè)窗口,下面我結(jié)合圖給大家分析一遍:
上圖中,現(xiàn)在我們有12個(gè)數(shù)據(jù)包需要發(fā)送,窗口大小為5,所以最多一次可連續(xù)發(fā)送5個(gè)數(shù)據(jù)包,假設(shè)現(xiàn)在窗口中的五個(gè)數(shù)據(jù)包都已經(jīng)發(fā)送完畢,此時(shí)收到了數(shù)據(jù)包1的確認(rèn)包,那么綠色窗口就可以往右邊移一個(gè)格子,如下圖:
上圖中,數(shù)據(jù)包6被滑進(jìn)格子里,此時(shí)數(shù)據(jù)包6就可以被發(fā)送,同時(shí)數(shù)據(jù)包1也可以從緩存中清除,通過這種方式可以提升信道的利用率從而提升傳輸效率,但這種傳輸方式也有一個(gè)缺點(diǎn),就是接收方每收到一個(gè)數(shù)據(jù)包都要進(jìn)行一次確認(rèn),這是完全沒必要的,我們可不可以這樣做:每收到5個(gè)數(shù)據(jù)包進(jìn)行一個(gè)確認(rèn),如下圖:
A一次給B發(fā)送了5個(gè)數(shù)據(jù)包,B確認(rèn)5個(gè)數(shù)據(jù)包都收到了,給A回復(fù)一個(gè)6,代表B已經(jīng)收到了前5個(gè)數(shù)據(jù)包讓A下次從第6個(gè)數(shù)據(jù)包開始發(fā)送,通過累積響應(yīng)這種方式又進(jìn)一步提升了傳輸效率,但這是理想情況下,如果說A發(fā)送完5個(gè)數(shù)據(jù)包,B只收到了1、2、4、5,數(shù)據(jù)包3丟了,怎么辦?是直接給A回復(fù)一個(gè)3嗎?是的話4、5都要進(jìn)行重傳,這樣就得不償失了,而編寫TCP協(xié)議那位老哥也想到了這種情況,所以就指定了相應(yīng)的策略,接著剛剛說,如果B確定數(shù)據(jù)包3丟了或者被阻塞了,那么它會(huì)立刻連續(xù)發(fā)送3個(gè)3,A收到連續(xù)的3個(gè)3后就認(rèn)為數(shù)據(jù)包3丟了,然后就會(huì)只補(bǔ)傳數(shù)據(jù)包3。
注意點(diǎn):
上面的內(nèi)容中我為了方便講解都是把數(shù)據(jù)包編成編號(hào)進(jìn)行描述,其實(shí)真正的數(shù)據(jù)包編號(hào)不是這樣的,TCP協(xié)議是面向字節(jié)流的,所以說序號(hào)和確認(rèn)號(hào)應(yīng)以字節(jié)為標(biāo)準(zhǔn),比如:A現(xiàn)在向B發(fā)送了5和數(shù)據(jù)包共100個(gè)字節(jié),B收到這5個(gè)數(shù)據(jù)包后會(huì)給A回復(fù)一個(gè)101,此時(shí)A就會(huì)從第101個(gè)字節(jié)開始進(jìn)行發(fā)送,以此類推。同時(shí)通過這種機(jī)制也可以實(shí)現(xiàn)斷點(diǎn)的下載。
5.5 流量控制
流量控制:用來協(xié)調(diào)server和client兩端因處理數(shù)據(jù)速度不同所帶來的問題。
舉個(gè)例子:
假如主機(jī)A要向主機(jī)B發(fā)送數(shù)據(jù),如果主機(jī)A發(fā)送數(shù)據(jù)的速度比主機(jī)B處理數(shù)據(jù)的速度要快,那么很可能導(dǎo)致主機(jī)B崩潰,通過TCP流量控制技術(shù)可以調(diào)整主機(jī)A發(fā)送數(shù)據(jù)的速度從而解決上面的問題。
TCP是怎樣實(shí)現(xiàn)流量控制的的?首先說明一點(diǎn),前面我們描述TCP傳輸數(shù)據(jù)的時(shí)候提到了滑動(dòng)窗口這個(gè)概念,其實(shí)不光發(fā)送方存在滑動(dòng)窗口,同樣接收方也存在滑動(dòng)窗口,接收方收到數(shù)據(jù)包后會(huì)將數(shù)據(jù)包放入滑動(dòng)窗口,對(duì)數(shù)據(jù)包操作完畢后將該數(shù)據(jù)包從滑動(dòng)窗口中移出,當(dāng)滑動(dòng)窗口被填滿時(shí)不可以再接收數(shù)據(jù),TCP中發(fā)送發(fā)窗口和接收方窗口大小是相同的。
所以,通過滑動(dòng)窗口機(jī)制可以實(shí)現(xiàn)流量控制,如下圖所示:
上圖中,B為發(fā)送方A為接收方,當(dāng)B與A建立連接的時(shí)候首先會(huì)明確自己滑動(dòng)窗口的大小,假如是10,B就會(huì)將rwnd(滑動(dòng)窗口)設(shè)置為10,A收到后也會(huì)將滑動(dòng)窗口設(shè)置為10,連接建立成功會(huì)A開始向B發(fā)送數(shù)據(jù),我們知道滑動(dòng)窗口越大發(fā)送的速度越快,假如rwnd=10時(shí)B處理數(shù)據(jù)包的速度小于接收數(shù)據(jù)包的速度那么滑動(dòng)窗口會(huì)逐漸被填滿,這樣會(huì)導(dǎo)致主機(jī)B中未處理的數(shù)據(jù)包越來越多最終可能會(huì)崩潰,為了避免這種情況的出現(xiàn),B可以在滑動(dòng)窗口被填滿了之后給A發(fā)送一個(gè)rwnd=6,A接收到rwnd=6后會(huì)將滑動(dòng)窗口調(diào)整為6進(jìn)而降低發(fā)送數(shù)據(jù)的速度,同樣B如果覺得A的發(fā)送速度過慢也可以通過設(shè)置rwnd的值來調(diào)整A的發(fā)送速度,B動(dòng)態(tài)的設(shè)置A的滑動(dòng)窗口就稱作為TCP流量控制技術(shù)。
5.6 擁塞避免
什么是擁塞呢?顧名思義就是賭了,數(shù)據(jù)被堵在半路了,那什么情況下會(huì)出現(xiàn)數(shù)據(jù)被堵在半路呢?
舉個(gè)例子:
假如現(xiàn)有兩臺(tái)主機(jī)分別是發(fā)送方主機(jī)A和接收方主機(jī)B,主機(jī)B的帶寬為50M/S,也就是說主機(jī)B每秒最多能接收50M的數(shù)據(jù),如果主機(jī)A的發(fā)送速度遠(yuǎn)低于50M/S,這種情況應(yīng)該是不會(huì)出現(xiàn)擁塞現(xiàn)象的,但是如果主機(jī)A的發(fā)送速度遠(yuǎn)大于50M/S,主機(jī)B的路由器接手不了這么多數(shù)據(jù)只能進(jìn)行丟棄,路由器也是有CPU、內(nèi)存和自己的操作系統(tǒng),當(dāng)主句A發(fā)送速度越快主機(jī)B的路由器CPU和內(nèi)存就要分配更多的資源去處理丟棄數(shù)據(jù)包,這樣就會(huì)導(dǎo)致接收數(shù)據(jù)包的速度越來越低,極端的情況下可能會(huì)出現(xiàn)主機(jī)B接收不到數(shù)據(jù)包的現(xiàn)象,也就是死鎖現(xiàn)象。
如果在進(jìn)行TCP數(shù)據(jù)傳輸?shù)臅r(shí)候不進(jìn)行流量控制很容易出現(xiàn)死鎖現(xiàn)象,因?yàn)榫W(wǎng)絡(luò)是大家共用的,所以避免網(wǎng)絡(luò)擁塞現(xiàn)象的出現(xiàn)需要所有計(jì)算機(jī)遵守一種特定的規(guī)則,那這種規(guī)則是怎樣控制網(wǎng)絡(luò)避免擁塞的呢?
先來看下面這張圖:
如果不進(jìn)行擁塞控制就是我們上面所說的,最終可能會(huì)出現(xiàn)上圖中綠線的情況,現(xiàn)在我們要通過擁塞控制使網(wǎng)絡(luò)數(shù)據(jù)傳輸按照上圖中藍(lán)線進(jìn)行。
下面我們來說一下如何進(jìn)行擁塞控制:
首先將滑動(dòng)窗口設(shè)置為1,然后再傳輸過程中逐漸以指數(shù)倍增加,當(dāng)滑動(dòng)窗口到達(dá)ssthresh的時(shí)候再以加法進(jìn)行增加,如果出現(xiàn)了擁塞現(xiàn)象就迅速再將滑動(dòng)窗口設(shè)置為1,ssthresh減小依次循環(huán),這種方式也稱為慢開始方式。但這種方式已經(jīng)被廢棄,因?yàn)槊看纬霈F(xiàn)擁塞的時(shí)候都會(huì)將滑動(dòng)窗口設(shè)置為0再進(jìn)行慢開始階段,這樣其實(shí)是完全沒必要的。
我們再來看升級(jí)版,如下圖:
在出現(xiàn)擁塞的時(shí)候并不會(huì)將滑動(dòng)窗口設(shè)置為1重新進(jìn)行慢開始,而是將滑動(dòng)窗口設(shè)置為出現(xiàn)擁塞時(shí)窗口的一半,然后再以加法進(jìn)行增加,此過程也可稱為是快恢復(fù),這樣就可以避免網(wǎng)絡(luò)擁塞的出現(xiàn)。
附錄:更多網(wǎng)絡(luò)編程文章
《技術(shù)往事:改變世界的TCP/IP協(xié)議(珍貴多圖、手機(jī)慎點(diǎn))》
《通俗易懂-深入理解TCP協(xié)議(上):理論基礎(chǔ)》
《通俗易懂-深入理解TCP協(xié)議(下):RTT、滑動(dòng)窗口、擁塞處理》
《理論經(jīng)典:TCP協(xié)議的3次握手與4次揮手過程詳解》
《理論聯(lián)系實(shí)際:Wireshark抓包分析TCP 3次握手、4次揮手過程》
《計(jì)算機(jī)網(wǎng)絡(luò)通訊協(xié)議關(guān)系圖(中文珍藏版)》
《UDP中一個(gè)包的大小最大能多大?》
《P2P技術(shù)詳解(一):NAT詳解——詳細(xì)原理、P2P簡介》
《P2P技術(shù)詳解(二):P2P中的NAT穿越(打洞)方案詳解》
《P2P技術(shù)詳解(三):P2P技術(shù)之STUN、TURN、ICE詳解》
《通俗易懂:快速理解P2P技術(shù)中的NAT穿透原理》
《高性能網(wǎng)絡(luò)編程(一):單臺(tái)服務(wù)器并發(fā)TCP連接數(shù)到底可以有多少》
《高性能網(wǎng)絡(luò)編程(二):上一個(gè)10年,著名的C10K并發(fā)連接問題》
《高性能網(wǎng)絡(luò)編程(三):下一個(gè)10年,是時(shí)候考慮C10M并發(fā)問題了》
《高性能網(wǎng)絡(luò)編程(四):從C10K到C10M高性能網(wǎng)絡(luò)應(yīng)用的理論探索》
《高性能網(wǎng)絡(luò)編程(五):一文讀懂高性能網(wǎng)絡(luò)編程中的I/O模型》
《高性能網(wǎng)絡(luò)編程(六):一文讀懂高性能網(wǎng)絡(luò)編程中的線程模型》
《不為人知的網(wǎng)絡(luò)編程(一):淺析TCP協(xié)議中的疑難雜癥(上篇)》
《不為人知的網(wǎng)絡(luò)編程(二):淺析TCP協(xié)議中的疑難雜癥(下篇)》
《不為人知的網(wǎng)絡(luò)編程(三):關(guān)閉TCP連接時(shí)為什么會(huì)TIME_WAIT、CLOSE_WAIT》
《不為人知的網(wǎng)絡(luò)編程(四):深入研究分析TCP的異常關(guān)閉》
《不為人知的網(wǎng)絡(luò)編程(五):UDP的連接性和負(fù)載均衡》
《不為人知的網(wǎng)絡(luò)編程(六):深入地理解UDP協(xié)議并用好它》
《不為人知的網(wǎng)絡(luò)編程(七):如何讓不可靠的UDP變的可靠?》
《技術(shù)掃盲:新一代基于UDP的低延時(shí)網(wǎng)絡(luò)傳輸層協(xié)議——QUIC詳解》
《讓互聯(lián)網(wǎng)更快:新一代QUIC協(xié)議在騰訊的技術(shù)實(shí)踐分享》
《現(xiàn)代移動(dòng)端網(wǎng)絡(luò)短連接的優(yōu)化手段總結(jié):請(qǐng)求速度、弱網(wǎng)適應(yīng)、安全保障》
《聊聊iOS中網(wǎng)絡(luò)編程長連接的那些事》
《移動(dòng)端IM開發(fā)者必讀(一):通俗易懂,理解移動(dòng)網(wǎng)絡(luò)的“弱”和“慢”》
《移動(dòng)端IM開發(fā)者必讀(二):史上最全移動(dòng)弱網(wǎng)絡(luò)優(yōu)化方法總結(jié)》
《IPv6技術(shù)詳解:基本概念、應(yīng)用現(xiàn)狀、技術(shù)實(shí)踐(上篇)》
《IPv6技術(shù)詳解:基本概念、應(yīng)用現(xiàn)狀、技術(shù)實(shí)踐(下篇)》
《從HTTP/0.9到HTTP/2:一文讀懂HTTP協(xié)議的歷史演變和設(shè)計(jì)思路》
《以網(wǎng)游服務(wù)端的網(wǎng)絡(luò)接入層設(shè)計(jì)為例,理解實(shí)時(shí)通信的技術(shù)挑戰(zhàn)》
《邁向高階:優(yōu)秀Android程序員必知必會(huì)的網(wǎng)絡(luò)基礎(chǔ)》
《全面了解移動(dòng)端DNS域名劫持等雜癥:技術(shù)原理、問題根源、解決方案等》
《美圖App的移動(dòng)端DNS優(yōu)化實(shí)踐:HTTPS請(qǐng)求耗時(shí)減小近半》
《Android程序員必知必會(huì)的網(wǎng)絡(luò)通信傳輸層協(xié)議——UDP和TCP》
>> 更多同類文章 ……
(本文同發(fā)布于:http://www.52im.net/thread-2216-1-1.html)