TCP选项:TCP_NODELAY和TCP_CORK
From: http://blog.163.com/zhangjie_0303/blog/static/990827062012718316231/
?
Nagle算法 TCP_NODELAY和TCP_CORK
Nagle算法
根據(jù)創(chuàng)建者John Nagle命名。該算法用于對(duì)緩沖區(qū)內(nèi)的一定數(shù)量的消息進(jìn)行自動(dòng)連接。該處理過程
(稱為Nagling),通過減少必須發(fā)送的封包的數(shù)量,提高了網(wǎng)絡(luò)應(yīng)用 程序系統(tǒng)的效率。Nagle算法
,由Ford Aerospace And Communications Corporation Congestion Control in IP/TCP
internetworks(IETF RFC 896)(1984)定義,最初是用于緩沖Ford的私有TCP/IP網(wǎng)絡(luò)擁塞情況,不
過被廣泛傳播開來(lái)。
Nagle的文檔定義了一種他稱之為小封包問題的解決方法。當(dāng)某個(gè)應(yīng)用程序每次只產(chǎn)生一字節(jié)的數(shù)
據(jù),就會(huì)導(dǎo)致網(wǎng)絡(luò)由于這樣的小封包而過載(該情況通 常被稱為“發(fā)送端SB窗口并發(fā)癥”),從
而產(chǎn)生該問題。一個(gè)源自鍵盤的單一字符-1字節(jié)的數(shù)據(jù)-可能導(dǎo)致一個(gè)41字節(jié)的封包被傳送,該
封包包含了1字節(jié)的 有用數(shù)據(jù)和40字節(jié)的頭部數(shù)據(jù)。這種4000%過載的情況,在像APRANET這樣只有
很輕負(fù)載的網(wǎng)絡(luò)中是可以接受的,但在像Ford這樣的負(fù)載很重的網(wǎng) 絡(luò)中,可能強(qiáng)制重傳,導(dǎo)致封
包丟失,并且通過過度擁擠交換節(jié)點(diǎn)和網(wǎng)關(guān)降低了傳播速度。更進(jìn)一步,當(dāng)連接被丟棄時(shí),吞吐量
可能被降低。Nagle算法-通常 的實(shí)現(xiàn)方法是在一個(gè)TCP程序中插入兩行代碼-在發(fā)送方,對(duì)標(biāo)識(shí)
為沒有回應(yīng)的數(shù)據(jù)進(jìn)行緩沖(存儲(chǔ))(這句怪怪的,其實(shí)應(yīng)該是對(duì)未發(fā)送數(shù)據(jù)按順序進(jìn)行緩沖,在
發(fā)送時(shí)進(jìn)行拼接)。順序發(fā)送的數(shù)據(jù)將被保持到接收到被標(biāo)識(shí)數(shù)據(jù)的回應(yīng)或者一整包有價(jià)值的數(shù)據(jù)
需要被發(fā)送。
雖然Nagle算法用于解決Ford網(wǎng)絡(luò)內(nèi)產(chǎn)生的問題,但同樣的問題也出現(xiàn)在APRANet。通過網(wǎng)絡(luò),
Nagling被廣泛實(shí)現(xiàn),包括 internet,并且產(chǎn)生了巨大的效用-雖然某些時(shí)候在高交互性環(huán)境如一
些C/S情況下不希望進(jìn)行該處理。在這種情況下,可以通過 TCP_NODELAY套接字選項(xiàng)關(guān)閉Nagling。
注:Nagle雖然解決了小封包問題,但也導(dǎo)致了較高的不可預(yù)測(cè)的延遲,同時(shí)降低了吞吐量。
實(shí)際上這就的你動(dòng)手來(lái)自己實(shí)現(xiàn)以下Nagle算法了。實(shí)際上Nagle算法并不是很復(fù)雜,他的主要職責(zé)
是數(shù)據(jù)的累積,實(shí)際上有兩個(gè)門檻:一個(gè)就是緩 沖區(qū)中的字節(jié)數(shù)達(dá)到了一定量,另一個(gè)就是等待
了一定的時(shí)間(一般的Nagle算法都是等待200ms);這兩個(gè)門檻的任何一個(gè)達(dá)到都必須發(fā)送數(shù)據(jù)了
。一般 情況下,如果數(shù)據(jù)流量很大,第二個(gè)條件是永遠(yuǎn)不會(huì)起作用的,但當(dāng)發(fā)送小的數(shù)據(jù)包時(shí),
第二個(gè)門檻就發(fā)揮作用了,防止數(shù)據(jù)被無(wú)限的緩存在緩沖區(qū)不是好事情哦。 了解了TCP的Nagle算
法的原理之后我們可以自己動(dòng)手來(lái)實(shí)現(xiàn)一個(gè)類似的算法了,在動(dòng)手之前我們還要記住一個(gè)重要的事
情,也是我們動(dòng)手實(shí)現(xiàn)Nagle算 法的主要?jiǎng)訖C(jī)就是我想要緊急發(fā)送數(shù)據(jù)的時(shí)候就要發(fā)送了,所以對(duì)
于上面的兩個(gè)門檻之外還的增加一個(gè)門檻就是緊急數(shù)據(jù)發(fā)送。現(xiàn)在可以開始工作了,我們這里主要
給出思路:
首先我們必須在SOCKET之上再建立一層,來(lái)定義我們的自己的傳輸控制,我們的Nagle算法也是在
這層里面實(shí)現(xiàn)的。?
Disable哪個(gè)TCP的Nagle算法,都自己動(dòng)手寫了,要它干嗎?
使 用Select函數(shù)來(lái)查看是否可以發(fā)送數(shù)據(jù),當(dāng)然我們實(shí)質(zhì)是否可寫的fd_set的時(shí)候需要加入我們
的三個(gè)門檻,首先是按照字節(jié)和緊急數(shù)據(jù)來(lái)檢查,一般情 況下這兩個(gè)條件就搞定了,然后再按照
時(shí)間來(lái)決定。我們可是使用一個(gè)累積字節(jié)記數(shù)器和一個(gè)等待時(shí)間計(jì)時(shí)器。累積字節(jié)記數(shù)器在每次添
加數(shù)據(jù)到我們的控制層的時(shí) 候就累加一下,發(fā)送完畢的時(shí)候減去響應(yīng)的字節(jié)數(shù);而計(jì)時(shí)器在第一
次將數(shù)據(jù)提交給控制層的時(shí)候啟動(dòng)(可以使用Windows的GetTickcount來(lái)得 到當(dāng)前的時(shí)間),然后
在每次發(fā)送數(shù)據(jù)完畢的時(shí)候重新復(fù)位一下。?
實(shí)際上這樣就已經(jīng)實(shí)現(xiàn)了Nagle算法,而且不需要經(jīng)常調(diào)用GetTickCount而降低了系統(tǒng)的性能。
TCP_CORK
TCP鏈接的過程中,默認(rèn)開啟Nagle算法,進(jìn)行小包發(fā)送的優(yōu)化。優(yōu)化網(wǎng)絡(luò)傳輸,兼顧網(wǎng)絡(luò)延時(shí)和網(wǎng)
絡(luò)擁塞。這個(gè)時(shí)候可以置位TCP_NODELAY關(guān)閉Nagle算法,有數(shù)據(jù)包的話直接發(fā)送保證網(wǎng)絡(luò)時(shí)效性。
在進(jìn)行大量數(shù)據(jù)發(fā)送的時(shí)候可以置位TCP_CORK關(guān)閉Nagle算法保證網(wǎng)絡(luò)利用性。盡可能的進(jìn)行數(shù)據(jù)
的組包,以最大mtu傳輸,如果發(fā)送的數(shù)據(jù)包大小過小則如果在0.6~0.8S范圍內(nèi)都沒能組裝成一個(gè)
MTU時(shí),直接發(fā)送。如果發(fā)送的數(shù)據(jù)包大小足夠間隔在0.45內(nèi)時(shí),每次組裝一個(gè)MTU進(jìn)行發(fā)送。如果
間隔大于0.4~0.8S則,每過來(lái)一個(gè)數(shù)據(jù)包就直接發(fā)送。
下面摘自:http://blog.csdn.net/lin49940/archive/2009/07/26/4382303.aspx
TCP_NODELAY 選項(xiàng)
設(shè)置該選項(xiàng): public void setTcpNoDelay(boolean on) throws SocketException?
讀取該選項(xiàng): public boolean getTcpNoDelay() throws SocketException?
???? 默認(rèn)情況下, 發(fā)送數(shù)據(jù)采用Negale 算法. Negale 算法是指發(fā)送方發(fā)送的數(shù)據(jù)不會(huì)立即發(fā)出,
而是先放在緩沖區(qū), 等緩存區(qū)滿了再發(fā)出. 發(fā)送完一批數(shù)據(jù)后, 會(huì)等待接收方對(duì)這批數(shù)據(jù)的回應(yīng),
然后再發(fā)送下一批數(shù)據(jù). Negale 算法適用于發(fā)送方需要發(fā)送大批量數(shù)據(jù), 并且接收方會(huì)及時(shí)作出
回應(yīng)的場(chǎng)合, 這種算法通過減少傳輸數(shù)據(jù)的次數(shù)來(lái)提高通信效率.
???? 如果發(fā)送方持續(xù)地發(fā)送小批量的數(shù)據(jù), 并且接收方不一定會(huì)立即發(fā)送響應(yīng)數(shù)據(jù), 那么Negale
算法會(huì)使發(fā)送方運(yùn)行很慢. 對(duì)于GUI 程序, 如網(wǎng)絡(luò)游戲程序(服務(wù)器需要實(shí)時(shí)跟蹤客戶端鼠標(biāo)的移
動(dòng)), 這個(gè)問題尤其突出. 客戶端鼠標(biāo)位置改動(dòng)的信息需要實(shí)時(shí)發(fā)送到服務(wù)器上, 由于Negale 算法
采用緩沖, 大大減低了實(shí)時(shí)響應(yīng)速度, 導(dǎo)致客戶程序運(yùn)行很慢.
下面摘自http://hi.baidu.com/dirlt/blog/item/5ea4be1795d30b03c83d6d7f.html
TCP_NODELAY和TCP_CORK
這里了解一下問題的背景就好理解了[不考慮滑動(dòng)窗口加入,只是說(shuō)packet的組織]
1.歷史上TCP是每發(fā)送一次包等待一個(gè)ACK然后下一個(gè)
2.但是在一些交互式應(yīng)用下比如Telnet,結(jié)果就是我們每按一次鍵就會(huì)發(fā)送一個(gè)packet.每一個(gè)字
符配一個(gè)TCP頭效率不高,那個(gè)Nagle算法出來(lái)了。發(fā)送方法送數(shù)據(jù)A時(shí)然后再等待接受方的ACK時(shí),
積累本地收集到的所有TCP數(shù)據(jù)包然后一次性發(fā)送。但是很明顯Nagle算法不利于交互式情景
3.但是現(xiàn)代應(yīng)用下面還是存在交互式應(yīng)用的,所以有時(shí)候我們需要關(guān)閉Nagle那么可以設(shè)置
TCP_NODELAY
4.但是Nagle組織包的長(zhǎng)度是由系統(tǒng)決定的,有時(shí)候我們知道我們會(huì)每個(gè)1分鐘產(chǎn)生1字節(jié),共1000
字節(jié)。如果完全由Nagle算法來(lái)發(fā)送的話,可能還是會(huì)1字節(jié)1字節(jié)發(fā)送[這是一種極端情況,假設(shè)返
回ACK時(shí)間不是很長(zhǎng)]。這個(gè)時(shí)候首先設(shè)置TCP_CORK能夠阻塞住TCP[盡量阻塞住],等我們write完
1000字節(jié)之后,取消TCP_CORK,這個(gè)時(shí)候就能夠?qū)?000字節(jié)一次發(fā)出
TCP_NODELAY和TCP_CORK都是禁用Nagle算法,只不過NODELAY完全關(guān)閉而TCP_CORK完全由自己決定
發(fā)送時(shí)機(jī)。Linux文檔上說(shuō)兩者不要同時(shí)設(shè)置。
總結(jié)
以上是生活随笔為你收集整理的TCP选项:TCP_NODELAY和TCP_CORK的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: android6.0闪光灯源码,andr
- 下一篇: c语言中如何进行开方和求一个数的几次方;