摘要
鑒于TCP傳輸控制過程比較復(fù)雜,單單看書就已經(jīng)看了3、4遍,為加深理解,本文主要對相關(guān)機制作一個通覽式的復(fù)習(xí)總結(jié)說明,如TCP是如何對成塊式數(shù)據(jù)流進(jìn)行流控的,慢啟動、擁塞避免的機制是什么;不涉及太深的細(xì)節(jié),文中大多內(nèi)容出自于《TCP/IP協(xié)議詳解 卷1:協(xié)議》。學(xué)識有限,如有錯漏,請不吝指正。
前置知識
閱讀本文需要具備的前置知識:
TCP/IP報文分組概念
ACK確認(rèn)概念
滑動窗口滑動過程
TCP應(yīng)用分類
如果從傳輸?shù)膽?yīng)用數(shù)據(jù)量級大小來看,TCP應(yīng)用可以分為兩大類:
交互式數(shù)據(jù)流。該類應(yīng)用每次要傳輸?shù)臄?shù)據(jù)通常都比較小,如telnet/secureCRT/terminal在客戶端連接上遠(yuǎn)程主機敲入Linux命令時,通常每敲入一個鍵都會傳輸一個數(shù)據(jù)分組到遠(yuǎn)程主機,遠(yuǎn)程主機收到該請求報文并且經(jīng)過業(yè)務(wù)邏輯處理后再回復(fù)回顯給客戶端,客戶端此時才將按鍵的字符顯示在屏幕上,那么在這個過程中,客戶端發(fā)送的數(shù)據(jù)分組除去TCP/IP報文頭后,實際傳輸?shù)臄?shù)據(jù)(鍵盤字母的字節(jié))是非常小的。另一個例子就是遠(yuǎn)程桌面軟件,滑動鼠標(biāo)時產(chǎn)生的眾多小報文分組。
成塊數(shù)據(jù)流。該類應(yīng)用每次傳輸?shù)臄?shù)據(jù)通常都較大,如ftp文件傳輸、email等。
在實際中要判斷一個應(yīng)用是屬于交互式數(shù)據(jù)流,還是屬于成塊數(shù)據(jù)流,還是需要根據(jù)具體的實際情況進(jìn)行判斷。
TCP基礎(chǔ)特性
TCP經(jīng)受時延確認(rèn)(ACK)
TCP在接收到數(shù)據(jù)時并不立即發(fā)送ACK,相反,TCP推遲發(fā)送,以便將ACK與需要沿該方向發(fā)送的數(shù)據(jù)一起發(fā)送(如果有新數(shù)據(jù)需要發(fā)送,則立即和ACK一起發(fā)送,否則等待,最大等待200ms)
重復(fù)確認(rèn)ACK
接收方每當(dāng)收到1個失序的報文,就重復(fù)一次失序前的那個報文的ACK。
交互式數(shù)據(jù)流的傳輸控制
從上一節(jié)可知,交互式數(shù)據(jù)流應(yīng)用的特點是,每次應(yīng)用要發(fā)送的數(shù)據(jù)量都比較?。óa(chǎn)生的報文分組很小,但每個分組的TCP/IP報文頭大小比應(yīng)用數(shù)據(jù)本身的大小要大很多,如20字節(jié)IP首部+20字節(jié)TCP首部+1字節(jié)應(yīng)用數(shù)據(jù)),當(dāng)網(wǎng)絡(luò)中出現(xiàn)了大量的小分組時(網(wǎng)絡(luò)中有很多用戶同時使用應(yīng)用),這在局域網(wǎng)中通常不會有問題(客戶端服務(wù)端都部署在局域網(wǎng)中),但在廣域網(wǎng)上就很可能會出現(xiàn)問題,中間要經(jīng)過好幾個路由,有可能會造成擁塞(總體TCP/IP報文頭大小占了大頭)。因此,這時可以考慮采用Nagle算法,通過該算法可以減少分組數(shù)目,緩解網(wǎng)絡(luò)擁塞。
Nagle算法
Nagle算法描述如下:
要求一個TCP連接上最多只能有一個未被確認(rèn)的分組,在該分組的ACK確認(rèn)達(dá)到之前不能發(fā)送其他的小分組。相反,Nagle算法會收集少量的正在等待的小分組,在ACK到來時以一個分組的方式發(fā)送出去。(可以理解為打包操作)
該算法是自適應(yīng)的:ACK達(dá)到的越快,數(shù)據(jù)也就發(fā)送得越快;反之ACK到達(dá)越慢,數(shù)據(jù)發(fā)送得也就越慢。從這里可以看出,nagle算法可以起到減少分組數(shù)量的作用,發(fā)送的分組少了,對網(wǎng)絡(luò)負(fù)載的沖擊也會相應(yīng)的降低,從而避免了進(jìn)一步的擁塞。
但如果在低速的廣域網(wǎng)上,對于要求數(shù)據(jù)實時、低時延傳輸?shù)膽?yīng)用,就會很可能出現(xiàn)更高的時延(因為本該一次全部發(fā)送出去的數(shù)據(jù),現(xiàn)在要分批發(fā)送,時延就更高了,本來從發(fā)送一次報文到相應(yīng)的ACK回來的這個過程時延就不低。如果接收端觸發(fā)了經(jīng)受時延確認(rèn)算法,則會更惡劣)。具體示例、闡述詳見《TCP/IP協(xié)議詳解 卷1:協(xié)議》-“關(guān)閉nagle算法”章節(jié)。
對于高速的局域網(wǎng),Nagle算法是否適用?
在以太網(wǎng)上一個字節(jié)被發(fā)送、確認(rèn)和回顯的平均往返時間約為16ms,按這個速度算,1s可以傳輸1000/16=62.5個字節(jié)。那么如果在局域網(wǎng)中,諸如telnet/terminal這類的程序,就會出現(xiàn)ACK確認(rèn)都回來了,新的按鍵數(shù)據(jù)還沒有出現(xiàn)的尷尬情況(手速太慢),因此也就無需nagle算法了,但對于其他應(yīng)用來說就另說了。
成塊數(shù)據(jù)流的傳輸控制
對于成塊數(shù)據(jù)流應(yīng)用,在發(fā)送數(shù)據(jù)時有兩種方式:
發(fā)送方在發(fā)送下一個數(shù)據(jù)塊之前需要等待接收方對接收數(shù)據(jù)的確認(rèn)(ACK),即發(fā)送-停止-等待確認(rèn)-發(fā)送;
發(fā)送方在停止等待確認(rèn)前可以連續(xù)發(fā)送多個分組
第一種方式比較少采用,一般是采用第二種方式,那么對于第二種方式,在一次停止等待確認(rèn)前是不是可以發(fā)送任意個分組? 在TCP中,發(fā)送端有有限的發(fā)送緩存、接收端有有限的接收緩存,發(fā)送端與接收端之間可能會經(jīng)過數(shù)個路由,而每個路由又有自身的緩存容量限制,如果發(fā)送端發(fā)送過多的分組突破了中間路由的緩存上限,那么會出現(xiàn)分組丟棄、網(wǎng)絡(luò)擁塞,又或者接收端本地已沒有足夠的空閑緩存空間,這些情況也會造成分組丟棄、繼而發(fā)送端不得不進(jìn)行超時重傳。因此,需要有合適的方法控制分組進(jìn)入網(wǎng)絡(luò)的速率以適應(yīng)當(dāng)前網(wǎng)絡(luò)情況,以及適應(yīng)接收端的接收能力。從發(fā)送端側(cè)實施的流控算法有慢啟動、擁塞避免,從接收端側(cè)實施的則有滑動窗口。
滑動窗口WND
滑動窗口:
由接收方控制,接收方根據(jù)本地TCP緩存剩余空閑空間多少進(jìn)行控制 通告 發(fā)送方。
可以看出,滑動窗口主要是接收端用于“告訴”發(fā)送端,“你下次最多能發(fā)送XXX字節(jié)數(shù)據(jù)過來,不能再大啦!”,這是接收段端的流控。
在局域網(wǎng)下,發(fā)送方一般可以一直發(fā)送多個報文段,直到達(dá)到接收方的窗口大小為止。但在廣域網(wǎng)下,如果兩者之間存在較慢的鏈路,中間的路由需要緩存分組,則發(fā)送過多的分組(雖然沒達(dá)到滑動窗口大?。┯锌赡艹霈F(xiàn)耗盡路由的緩存、丟棄分組,從而擁塞網(wǎng)絡(luò)。分組丟失給發(fā)送方最直觀的指示(表現(xiàn))是:
超時,發(fā)出去分組后很久都沒有對應(yīng)的ACK;
收到重復(fù)的確認(rèn),接收端接收到失序的報文,中間有報文沒達(dá)到;
TCP根據(jù)不同的分組丟失指示執(zhí)行不同流控策略,如果是“超時”,則接下來發(fā)送端執(zhí)行“慢啟動”策略,如果是“收到重復(fù)的確認(rèn)”,則執(zhí)行“快速重傳-快速恢復(fù)-擁塞避免”策略;無論執(zhí)行何種策略,TCP對一個TCP連接維護(hù)兩個關(guān)鍵變量:
擁塞窗口CWND,描述了發(fā)送方感受到的網(wǎng)絡(luò)擁塞的估計
慢啟動閥門sstresh
在建立連接后,對CWND初始化為1個報文段,sstresh為65535個字節(jié)。當(dāng)擁塞發(fā)生時,設(shè)置慢啟動閥門sstresh值為當(dāng)前擁塞窗口cwnd的一半。
慢啟動
慢啟動算法簡要描述如下:
發(fā)送方初始化cwnd為1個報文段
每收到一個ACK就增加一個報文段(可以認(rèn)為是一種指數(shù)增長)
cwnd上限取cwnd與wnd最小值,也就是最多不超過對方通告的滑動窗口
一直持續(xù)到當(dāng)擁塞發(fā)生時所處位置一半的時候才停止(cwnd==sstresh),然后轉(zhuǎn)而執(zhí)行擁塞避免
擁塞避免
擁塞避免算法如下:
每次收到一個ACK時將cwnd增加1/cwnd(可以認(rèn)為是加性增長)
直到發(fā)送方與接收方之間的管道被填滿(cwnd==wnd),此時分組進(jìn)入網(wǎng)絡(luò)的速率與回復(fù)確認(rèn)的速率基本相同
快速重傳
快速重傳是在發(fā)送方接收到3個或以上的重復(fù)ACK時執(zhí)行的策略,這種情況下沒有執(zhí)行慢啟動的原因是 由于收到重復(fù)的ACK不僅僅是告訴我們有一個分組已經(jīng)丟失,還意味著接收端還接收到了該ACK標(biāo)記的序號以后的報文組,因為接收端只有在接收到另一個報文(斷序后面的)才會發(fā)送一個重復(fù)的ACK,也就是說,在收發(fā)兩端仍然有流動的數(shù)據(jù),此時不希望執(zhí)行慢啟動來突然減少數(shù)據(jù)流??焖僦貍骱涂焖倩謴?fù)算法描述如下:
當(dāng)收到第3個重復(fù)的ACK時,馬上重傳丟失的報文,不用等到定時器溢出,將sstresh設(shè)置為當(dāng)前窗口cwnd的一半,設(shè)置cwnd為sstresh+3倍報文段大?。ǎ?/p>
每收到另一個重復(fù)的ACK,cwnd增加一個報文段大小并發(fā)送一個新的分組;
當(dāng)下一個確認(rèn)新數(shù)據(jù)的ACK到達(dá)時,設(shè)置cwnd=sstresh(快速重傳中設(shè)置的值),這個ACK應(yīng)該是進(jìn)行重傳后的一個往返時間內(nèi)對重傳步驟的確認(rèn),也是對丟失的分組和收到的第1個重復(fù)的ACK之間所有的中間報文段的確認(rèn),此時可以認(rèn)為快速重傳、恢復(fù)已結(jié)束,接下來要執(zhí)行擁塞避免,降低分組進(jìn)入網(wǎng)絡(luò)的速率(減半)。
小結(jié)
以上簡要總結(jié)了TCP交互式數(shù)據(jù)流、成塊數(shù)據(jù)流的流控機制,其中成塊數(shù)據(jù)流流控的一個核心思想是發(fā)送報文組的數(shù)量先從1開始緩慢的指數(shù)增長(慢啟動),然后再加性增長, 直至分組進(jìn)入網(wǎng)絡(luò)的速率與回復(fù)的速率基本相當(dāng)。如果擁塞,則根據(jù)分組丟失的指示來執(zhí)行慢啟動或快速重傳,無論執(zhí)行何種策略,目的只有一個,那就是將分組進(jìn)入網(wǎng)絡(luò)的速率減半以緩解當(dāng)前的網(wǎng)絡(luò)擁塞狀況。整體梳理一遍,如下圖所示:

引用參考
《TCP/IP協(xié)議詳解 卷1:協(xié)議》.W.Richard Stevens