Socket詳解---Delayed Ack(Ack確認(rèn)延遲) && Nagle Algorithm(納格算法)

如果一個(gè) TCP 連接的一端啟用了 Nagle‘s Algorithm,而另一端啟用了 TCP Delayed Ack,而發(fā)送的數(shù)據(jù)包又比較小,則可能會(huì)出現(xiàn)這樣的情況:發(fā)送端在等 待接收端對(duì)上一個(gè)packet 的 Ack 才發(fā)送當(dāng)前的 packet,而接收端則正好延遲了 此 Ack 的發(fā)送,那么這個(gè)正要被發(fā)送的 packet 就會(huì)同樣被延遲。當(dāng)然 Delayed Ack 是有個(gè)超時(shí)機(jī)制的,而默認(rèn)的超時(shí)正好就是40ms。

1.Delayed Ack

tcp協(xié)議規(guī)定在接受到數(shù)據(jù)段時(shí)需要向?qū)Ψ桨l(fā)送一個(gè)確認(rèn),但如果只是單純的發(fā)送一個(gè)確認(rèn),代價(jià)會(huì)比較高(20字節(jié)的ip首部,20字節(jié)的tcp首部),最好能附帶響應(yīng)數(shù)據(jù)一起發(fā)送給對(duì)?方.所以tcp在何時(shí)發(fā)送ack給對(duì)方有以下規(guī)定:

1) 當(dāng)有響應(yīng)數(shù)據(jù)要發(fā)送時(shí),ack會(huì)隨響數(shù)據(jù)立即發(fā)送給對(duì)方.

2) 如果沒有響應(yīng)數(shù)據(jù),ack的發(fā)?送將會(huì)有一個(gè)延遲,以等待看是否有響應(yīng)數(shù)據(jù)可以一起發(fā)送?,這稱是"Delayed Ack".但這個(gè)延遲最多不會(huì)超過500ms,一般為200ms.如果在200ms內(nèi)有數(shù)據(jù)要發(fā)送,那么ack會(huì)隨數(shù)據(jù)一起立即發(fā)送給對(duì)方.注意這里的延遲200ms,不是指的從接受到對(duì)方數(shù)據(jù)到發(fā)送ack的最長等待時(shí)間差.而是指的內(nèi)核啟動(dòng)的一個(gè)定時(shí)器,它每隔200ms就查看下是否有ack要發(fā)送.例如:假設(shè)定時(shí)器在0ms時(shí)啟動(dòng),對(duì)方的數(shù)據(jù)段在

185ms時(shí)到達(dá),那么ack最遲會(huì)在200ms時(shí)發(fā)送,而不是385ms時(shí)發(fā)送.

3) 如果在等待發(fā)送ack期間,對(duì)方的第二個(gè)數(shù)據(jù)段又到達(dá)了,這時(shí)要立即發(fā)送ack.但是如果對(duì)方的三個(gè)數(shù)據(jù)段相繼?到達(dá),那么第二個(gè)數(shù)據(jù)段到達(dá)時(shí)ack立即發(fā)送,但第三個(gè)數(shù)據(jù)段到達(dá)時(shí)是否立即發(fā)送,則取決于上面兩條.

2.Nagle Algorithm

當(dāng)tcp協(xié)議用來傳輸小的數(shù)據(jù)段時(shí)代碼是很高的,并且如果傳輸是在廣域網(wǎng)上,那可能就會(huì)引起網(wǎng)絡(luò)擁塞.Nagle算法就是用來解決這個(gè)問題.該算法要求一個(gè)TCP連接上最多只能有一個(gè)未被確認(rèn)(未收到Ack確認(rèn))的未完成的小分組,在該分組的確認(rèn)到達(dá)之前不能發(fā)送其他的小分組。相反TCP收集這些少量的分組,并在確認(rèn)到來時(shí)以一?個(gè)分組的方式發(fā)出去.Host Requirements RFC聲明TCP必須實(shí)現(xiàn)Nagle算法,但必須為應(yīng)用提供一種方法來關(guān)閉該算法在某個(gè)連接上執(zhí)行。

納格算法是合并(coalescing)一定數(shù)量的輸出資料后一次送出。特別的是,只要有已送出的封包尚未確認(rèn),傳送者會(huì)持續(xù)緩沖封包,直到累積一定數(shù)量的資料才送出。

算法如下如下:

if 有新資料要傳送

if 訊窗大小 >= MSS and 可傳送的資料 >= MSS

? ? 立刻傳送完整MSS大小的segment

else

? ? ?if ?管線中有尚未確認(rèn)的資料

? ? ? ? ?在下一個(gè)確認(rèn)(ACK)封包收到前,將資料排進(jìn)緩沖區(qū)佇列

? ? ?else

? ? ? ? ?(?MSS=最大segment大小)

為什么要同時(shí)介紹這兩個(gè)知識(shí)呢?

因?yàn)檫@兩個(gè)技術(shù)同時(shí)使用的話會(huì)出現(xiàn)問題,下面來看一下問題的出現(xiàn)場景:

A 和B進(jìn)行數(shù)據(jù)傳輸 : ?A運(yùn)行Nagle算法,B運(yùn)行delayed ACK算法

1. A->B 發(fā)一個(gè)packet(數(shù)據(jù)包), B不回應(yīng),delay ACK

2. A-> 再發(fā)一個(gè)packet(數(shù)據(jù)包)

3. B收到第二個(gè)packet(數(shù)據(jù)包),這時(shí)候會(huì)回應(yīng)第一個(gè)packet(數(shù)據(jù)包),即第一個(gè)ACK

4. 假設(shè)這時(shí)候A里的數(shù)據(jù)已經(jīng)

此時(shí)問題就來了,因?yàn)锳沒有收到第二個(gè)packet的ACK確認(rèn),同時(shí)數(shù)據(jù)

當(dāng)然我們從上面可以看到這種等待機(jī)制還是有副作用的,那就是需要等待:一項(xiàng)數(shù)據(jù)表明:

在以太網(wǎng)上,傳輸100000字節(jié)僅需1ms,但由于delayed ack和nagle的作用卻要花費(fèi)201ms,這顯然對(duì)程序的效率產(chǎn)生了很大影響.

TCP/IP協(xié)議中,無論發(fā)送多少數(shù)據(jù),總是要在數(shù)據(jù)前面加上協(xié)議頭,同時(shí),對(duì)方接收到數(shù)據(jù),也需要發(fā)送ACK表示確認(rèn)。為了盡可能的利用網(wǎng)絡(luò)帶寬,TCP總是希望盡可能的發(fā)送足夠大的數(shù)據(jù)。(一個(gè)連接會(huì)設(shè)置MSS參數(shù),因此,TCP/IP希望每次都能夠以MSS尺寸的數(shù)據(jù)塊來發(fā)送數(shù)據(jù))。

Nagle算法就是為了盡可能發(fā)送大塊數(shù)據(jù),避免網(wǎng)絡(luò)中充斥著許多小數(shù)據(jù)塊。

Nagle算法的基本定義是任意時(shí)刻,最多只能有一個(gè)未被確認(rèn)的小段。

所謂“小段”,指的是小于MSS尺寸的數(shù)據(jù)塊,

所謂“未被確認(rèn)”,是指一個(gè)數(shù)據(jù)塊發(fā)送出去后,沒有收到對(duì)方發(fā)送的ACK確認(rèn)該數(shù)據(jù)已收到。

舉個(gè)例子,比如之前的blog中的實(shí)驗(yàn),一開始client端調(diào)用socket的write操作將一個(gè)int型數(shù)據(jù)(稱為A塊)寫入到網(wǎng)絡(luò)中,由于此時(shí)連接是空閑的(也就是說還沒有未被確認(rèn)的小段),因此這個(gè)int型數(shù)據(jù)會(huì)被馬上發(fā)送到server端,接著,client端又調(diào)用write操作寫入‘/r/n’(簡稱B塊),這個(gè)時(shí)候,A塊的ACK沒有返回,所以可以認(rèn)為已經(jīng)存在了一個(gè)未被確認(rèn)的小段,所以B塊沒有立即被發(fā)送,一直等待A塊的ACK收到(大概40ms之后),B塊才被發(fā)送。整個(gè)過程如圖所示:


這里還隱藏了一個(gè)問題,就是A塊數(shù)據(jù)的ACK為什么40ms之后才收到?這是因?yàn)門CP/IP中不僅僅有nagle算法,還有一個(gè)ACK延遲機(jī)制。當(dāng)Server端收到數(shù)據(jù)之后,它并不會(huì)馬上向client端發(fā)送ACK,而是會(huì)將ACK的發(fā)送延遲一段時(shí)間(假設(shè)為t),它希望在t時(shí)間內(nèi)server端會(huì)向client端發(fā)送應(yīng)答數(shù)據(jù),這樣ACK就能夠和應(yīng)答數(shù)據(jù)一起發(fā)送,就像是應(yīng)答數(shù)據(jù)捎帶著ACK過去。在我之前的時(shí)間中,t大概就是40ms。這就解釋了為什么'/r/n'(B塊)總是在A塊之后40ms才發(fā)出。

如果你覺著nagle算法太搗亂了,那么可以通過設(shè)置TCP_NODELAY將其禁用。當(dāng)然,更合理的方案還是應(yīng)該使用一次大數(shù)據(jù)的寫操作,而不是多次小數(shù)據(jù)的寫操作。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容