• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>

            大龍的博客

            常用鏈接

            統(tǒng)計

            最新評論

            (TCP-over-UDP library):基于UDP協(xié)議之上實現(xiàn)通用、可靠、高效的TCP協(xié)議 ---------- 轉(zhuǎn)

            隨著互聯(lián)網(wǎng)應用廣泛推廣,出現(xiàn)了越來越多的網(wǎng)絡應用,其中基于p2p思想的各種網(wǎng)絡技術(shù)的產(chǎn)品也越來越多的出現(xiàn)在我們的視野當中。從最早聞名的Napster到現(xiàn)在的Bittorrent、eMule、skype等產(chǎn)品,P2P這種網(wǎng)絡應用模式已經(jīng)從各個方面深入人心。這些產(chǎn)品在各自的網(wǎng)絡實現(xiàn)技術(shù)上,都以各自的方法解決著同樣面臨的一個問題,如何讓他們的軟件產(chǎn)品在各異的網(wǎng)絡拓撲結(jié)構(gòu)中順利的進行P2P通信。
             眾所周知,在當今的網(wǎng)絡拓撲結(jié)構(gòu)中,普遍存在使用NAT設(shè)備來進行網(wǎng)絡地址轉(zhuǎn)換,而讓應用程序能跨越這些NAT設(shè)備進行全雙工的通信,就成為非常重要的一個問題。對于實現(xiàn)跨越NAT通信可以采取很多種辦法(對于能夠直接連接、反向連接的情況不在此列):首先是通過服務器進行轉(zhuǎn)發(fā),這是比較粗暴的方法,而且在用戶量大的時候,轉(zhuǎn)發(fā)服務器需要付出相當大的代價;第二,可以使用NAT穿透技術(shù)。而大家知道關(guān)于NAT穿透中,UDP穿透的成功率比起TCP穿透要高出許多,這一點這里將不做多述,可以參考Bryan Ford的文章《Peer-to-Peer Communication Across Network Address Translators》(http://www.brynosaurus.com/pub/net/p2pnat/)。因此在UDP協(xié)議上構(gòu)建一些大型的網(wǎng)絡應用程序可能會成為很多人的需求。
             當然也可能基于更多的原因,會有很多人希望能在UDP協(xié)議上進行大型應用程序的構(gòu)建。然而UDP協(xié)議本身存在著不通信不可靠的缺點,于是對于基于UDP進行可靠通信的需求就浮現(xiàn)出來了。目前在網(wǎng)絡上有許多人正做著這一工作,UDT、RakNet、eNet等都是構(gòu)建在UDP之后網(wǎng)絡可靠通信開發(fā)庫。然后這些庫開發(fā)時都針對了一些特殊應用來進行設(shè)計的,不具備通用性。比如RakNet是為游戲應用而設(shè)計,對于實時性等游戲相關(guān)的網(wǎng)絡需求有很好的支持,對于大批量數(shù)據(jù)傳輸卻有點力所不及。而UDT基于一種基于帶寬速率控制的擁塞控制算法進行設(shè)計(http://udt.sourceforge.net/doc/draft-gg-udt-01.txt),主要用在小數(shù)量的bulk源共享富裕帶寬的情況下,最典型的例子就是建立在光纖廣域網(wǎng)上的網(wǎng)格計算,而在ISP提供帶寬有限的情況下運行卻顯得消耗資源并性能不足。甚至可能被防火墻,或ISP服務商判斷為惡意帶寬使用攻擊。這些都使用得他們不能被廣泛地用于各種網(wǎng)絡應用程序。另外大家也陸續(xù)發(fā)現(xiàn)目前的UDT實現(xiàn)版本存在的一些問題。比如UDT做服務端接收連接時,總是新開一個端口與客戶端進行連接,這樣會帶來幾個問題:1)較多客戶端連接上來時,服務端新打開的眾多端口中可能有的端口會被防火墻攔截而導致通信失敗,2)如果客戶端處于Symmetric NAT和Port-Restricted Cone NAT后面時,將導致服務器端與客戶端連接無法成功建立,3)由于udp端口數(shù)最大值有限,所以UDT服務器端可接收的連接數(shù)也因些受限。再有就是不僅僅是UDT庫,基本上所有的UDP-based可靠通信庫,都未提供穿越proxy代理的功能(socks5);再有就是對UDP打洞技術(shù)有的支持得不完善或并不支持。
             基于這些原因,使得我需要開發(fā)一個基于UDP協(xié)議之上實現(xiàn)一個可靠、高效、通用的通信庫,來滿足我目前所開發(fā)的項目的需要。TCP協(xié)議算法已經(jīng)是經(jīng)過多方面及多年的驗證,是最具通用性,且可靠高效的。雖然UDT等各種庫指出TCP在這樣或那樣的網(wǎng)絡環(huán)境下存在不足,但眾多實現(xiàn)當中他仍然是最通用、可靠、高效的。相信有許多人跟我一樣,需要這么一個開發(fā)庫,所以我打算在開發(fā)過程中,陸續(xù)公開相關(guān)的文檔及這個開發(fā)庫。
             
            二、設(shè)計目標
             
             TDP主要的目標就是在UDP層之上實現(xiàn)TCP的協(xié)議算法,使得應用程序能夠在UDP層之上獲得通用、可靠、高效的通信能力。
             TDP網(wǎng)絡開發(fā)庫所實現(xiàn)的算法,都來自久經(jīng)考驗的TCP協(xié)議算法,網(wǎng)上有著非常多的參考資料。在實現(xiàn)當中,參考最多的是Richard Stevens的《TCP/IP詳解》。
             TDP提供的用于開發(fā)的應用程序接口與Socket API非常相像,姑且稱之為TDP Socket API,基本上的函數(shù)名與參數(shù)等都與Socket API相一致,但是TDP Socket API的API接口都位于命名空間TDP當中。只要使用過Socket API進行開發(fā)過的朋友,將都會使用TDP庫進行開發(fā)。下圖為TDP及TDP Socket API所處在的協(xié)議棧應用中的位置,以及與TCP協(xié)議棧應用的對比。
             
             
            三、協(xié)議說明
             
             1.協(xié)議格式
             
             TDP的實現(xiàn)的算法雖然與TCP實現(xiàn)的算法是大致相同的,但TDP的協(xié)議格式只是從TCP協(xié)議格式獲得參考,但并不完全與他相同。TDP的協(xié)議格式如下:
             
             
             
             接下來介紹一下協(xié)議格式的各個字段含義。
             4位首部長度:表示用戶數(shù)據(jù)在數(shù)據(jù)包中的起始位置。
             LIV:連接保活標志,用于表示TDP連接通路存活狀態(tài)。
             ACK:確認序號有效。
             PSH:接收方應該盡快將這個報文段交給應用層。
             RST:重建連接。
             SYN:同步序號用來發(fā)起一個連接。
             FIN:發(fā)端完成發(fā)送任務。
             16位窗口大小:接收端可接收數(shù)據(jù)的窗口大小。
             選項:只有一個選項字段,為最長報文大小,即MSS。TDP選項格式與TCP選項格式一致,kind=0時表示選項結(jié)束,kind=1時表示無操作,kind=2時表示最大報文段長度。如下圖:
             
             
             
             數(shù)據(jù):用戶通過TDP傳輸?shù)臄?shù)據(jù)。
             
             2.TDP連接建立與終止
             
             TDP的連接建立與終止可以參考TCP的狀態(tài)變遷圖(此圖的詳細解釋請參考《TCP/IP詳解 卷一》第18章),如下:
             
             
             2.1連接建立
             
             2.1.1三次握手
             連接建立分要經(jīng)過三次握手過程:1)客戶端發(fā)送一個SYN段到指明客戶打算連接的服務器的端口,報文段中要設(shè)置客戶端初始序號。2)服務器發(fā)回包含服務器的初始序號的SYN報文段作為應答。同時,將確認序號設(shè)置為客戶的初始序號加1,并設(shè)置ACK位標志報文段為確認報文段。3)客戶端必須將確認序號設(shè)置為服務器初始序號加1,對服務器的SYN報文段進行確認。
             TDP在全局維護一個初始序號種子,這個初始序號為隨時產(chǎn)生的32位整數(shù)。
             連接建立的超時和重傳初始值為3秒,超時采用指數(shù)退避算法,3秒超時后超時值為6秒,然后是12秒,24秒……。連接建立最長時間限制為75秒。
             
             2.1.2 NAT UDP PUNCH模式
             當TDP工作模式是NAT UDP PUNCH時,在三次握手之前,向?qū)Χ薔AT端口及預測端口間隔默認2ms發(fā)送默認為10個LIV報文段,一來用于打開自已的NAT端口,二來是用于進入對端NAT端口。默認值可以由用戶程序設(shè)置。這時的LIV報文段中初始序號及確認序號都為0。
             當接收到對端LIV報文段后,立即停止LIV報文段發(fā)送,發(fā)出SYN報文段進行連接建立。這時有兩種可能:其一是另一端直到接收到該SYN報文段之前,都沒有接收到LIV報文段,或是剛接收到但沒有來得及發(fā)送SYN報文段,此時將會如上文描述的正常模式下連接建立的過程一致,將經(jīng)歷三次握手。基二是另一端在接收到該SYN報文段之前,也已經(jīng)發(fā)送出SYN報文段,此時雙方都需要對SYN報文段進行確認,可以稱之為四次握手。

             2.1.3 最大傳輸報文大小(MSS)
             TCP報文段在連接建立時需要通報MSS,在TDP的實現(xiàn)中也進行通報,默認通報為1460字節(jié)(符合以太網(wǎng)標準,這個默認值允許20字節(jié)的IP首部、8字節(jié)的UDP首部和12字節(jié)的TDP首部,以適合 1500字節(jié)的IP數(shù)據(jù)報)默認值可以由用戶程序設(shè)置。
             TCP在對端地址為非本地IP時,默認通報為536字節(jié)。TDP之所以默認通報為1460,是因為TDP在數(shù)據(jù)傳輸過程中,實現(xiàn)了路徑MTU發(fā)現(xiàn)技術(shù),通過實際發(fā)現(xiàn)的MTU,進行MSS的動態(tài)調(diào)整,以盡量避免報文段在網(wǎng)絡中的傳輸產(chǎn)生分片的情況。路徑MTU發(fā)現(xiàn)技術(shù)在傳輸數(shù)據(jù)流一節(jié)中進行描述。
             
             2.1.4 半打開連接及連接保活
             半打開連接是指對端異常關(guān)閉,如網(wǎng)線拔掉、突然斷電等情況將引發(fā)一端導演關(guān)閉,而另一端的連接卻仍然認為連接處于打開當中,這種情況稱之為半打開連接。TDP中的一個TDP SOCKET描述符由本地IP、本地端口、遠端IP、遠端端口唯一確定。當遠端客戶端連接請求到來時,服務端將接收到一個新的TDP SOCKET描述符,當這一個描述符唯一確定信息已經(jīng)存在時,對新的連接請求發(fā)送RST報文段,通知其重置連接請求。對于舊的連接,由保活機制自動發(fā)現(xiàn)是否為半打開連接,如果是半打開連接,則自動關(guān)閉該連接。這里RST報文段與TCP中的RST報文段有些不一樣,TCP的RST報文段工作描述請參考《TCP/IP詳解 卷一》。
             連接建立之后,TDP連接需要啟動保活機制。TCP連接在沒有數(shù)據(jù)通信的情況下也能保持連接,但TDP連接不行。TDP連接在一定時間段內(nèi)如果沒有數(shù)據(jù)交互的話,將主動發(fā)送保活LIV報文段。這個時間段根據(jù)TDP連接工作模塊不同有所差異,在NAT UDP PUNCH模式下,這個時間段默認值為1分鐘(大多數(shù)的NAT中,UDP會話超時時間為2-5分鐘左右);而在常規(guī)模塊下這個時間段默認值為5分鐘。默認值可以由用戶程序設(shè)置,用戶程序需要指明兩種模塊下的保活時間周期。這里TDP的保活機制與TCP中的保活機制完全不一樣,TCP的保活機制描述請參考《TCP/IP詳解 卷一》。
             
             2.2連接關(guān)閉
             
             TDP連接與TCP連接一樣是全雙工的,因此每個方向必須單獨地進行關(guān)閉。客戶機給服務器一個FIN報文段,然后服務器返回給客戶端一個確認ACK報文,并且發(fā)送一個FIN報文段,當客戶機回復ACK報文后(四次握手),連接就結(jié)束了。
             TDP連接的一端接收到FIN報文段時,如果還有數(shù)據(jù)要發(fā)送,需要繼續(xù)將數(shù)據(jù)進行發(fā)送完成,然后才發(fā)出FIN報文段;如果還有數(shù)據(jù)未從緩存中取出,將取出數(shù)據(jù),并進行確認,直到所有確認完成之后,然后才發(fā)出FIN報文段(此時如果有亂序的報文段情況不進行處理)。上面的描述也表現(xiàn)出,TDP是支持半關(guān)閉的,當一端發(fā)出FIN報文段時,仍然允許接收另一端數(shù)據(jù)。但是半關(guān)閉可能導致連接永遠停留在狀態(tài)圖中FIN_WAIT_2狀態(tài)中,此時保活機制仍然在工作當中,如果對端已經(jīng)關(guān)閉,那么保活機制將在檢測到時立即關(guān)閉這一連接。
             
             下圖是一個典型的連接建立與連接關(guān)閉的示意圖,此圖摘自《TCP/IP詳解 卷一》。
             
             
             
            四、TDP傳輸數(shù)據(jù)流
             
             1.傳輸?shù)膱笪亩?br> 
             在TDP工作過程中傳輸?shù)乃袌笪亩危挥蠸YN報文段、FIN報文段、數(shù)據(jù)報文段是可靠的之外,其它報文段如ACK報文段、LIV報文段、RST報文段等都不是可靠的。SYN報文段與FIN報文段傳輸中都占用一個序號,數(shù)據(jù)報文段在傳輸中根據(jù)傳輸?shù)臄?shù)據(jù)字節(jié)數(shù)占用相應的序號,其它報文段不占用傳輸序號。
             成功接收數(shù)據(jù)報文段,應當將按序?qū)ο乱粋€期望的數(shù)據(jù)報文段的序號作為確認序號發(fā)送ACK報文段進行確認。當出現(xiàn)接收到亂序的數(shù)據(jù)報文段時,將亂序數(shù)據(jù)報文段按序緩存,并發(fā)送期望報文段的ACK報文段進行確認。ACK報文段的發(fā)送并非即時的,也并非是對應接收數(shù)據(jù)報進行一對一確認發(fā)送。ACK報文段由200ms定時觸發(fā)發(fā)送,也就是說ACK報文段要經(jīng)受最多200ms的時延進行發(fā)送。ACK報文段對此時期望的數(shù)據(jù)序號進行確認,因此并不是與接收數(shù)據(jù)報相對應。ACK報文段是不可靠的,當丟失時對端將無法了解接收情況,因此發(fā)送方將會有一個超時機制,如果發(fā)現(xiàn)確認的ACK報文段超時,發(fā)送方將重發(fā)該數(shù)據(jù)報,這一點在第五節(jié)進行詳細描述。
             
             2.路徑MTU發(fā)現(xiàn)及MSS通告
             
             前面已經(jīng)提到要在連接建立過程中會通告初始MSS,這個值可以由用戶程序進行設(shè)置。但這個初始值是一個靜態(tài)的。當通信的兩個端點之間跨越多個網(wǎng)絡時,使用設(shè)置的MSS進行報文段發(fā)送時,可能導致傳輸?shù)腎P報文分片情況的產(chǎn)生。為了避免分片情況的產(chǎn)生,TDP在數(shù)據(jù)傳輸過程中進行動態(tài)的路徑MTU發(fā)現(xiàn),并進行MSS的更新及通告。
             TDP創(chuàng)建UDP SOCKET時,即將描述符設(shè)置IP選項為不允許進行分片(setsockopt (clientSock, IPPROTO_IP, IP_DONTFRAGMENT,(char*)&dwFlags, sizeof(dwFlags)))。在發(fā)送數(shù)據(jù)時以當前MSS大小值進行數(shù)據(jù)發(fā)送,如果返回值為錯誤碼WSAEMSGSIZE(10040)表示為報文段盡寸大于MTU,需要進行IP分片傳輸。此時,縮減MSS大小再次進行報文段發(fā)送,直至不再返回錯誤碼WSAEMSGSIZE(10040)。當MSS變更并能成功發(fā)送報文段后,需要向?qū)Χ送▓笮碌腗SS值。每次MSS縮小后,默認隔30秒,TDP將默認擴大MSS大小,以檢查是否路徑MTU增大了(默認值可以由用戶程序設(shè)置),之后隔30*2秒、30*2*2秒進行檢測,如果三次都未發(fā)現(xiàn)MTU增大則停止進行檢測。見RFC1191描述,網(wǎng)絡中MTU值的個數(shù)是有限的,如下圖描述(摘自RFC1191)。因此MSS的擴大及縮減,可依據(jù)一些由近似值按序構(gòu)成的表,依照此表索引進行MSS值的擴大與縮減計算。
             
             TDP中MSS與MTU之間關(guān)系的計算公式如下:
             MSS = MTU – 20(IP首部) – 8(UDP首部) – 12(TDP首部)。
             
             3.Nagle算法
             
             有些人誤認為經(jīng)受時延的捎帶ACK發(fā)送是Nagle算法,其實不是。經(jīng)受時延的捎帶ACK發(fā)送是TCP的通常實現(xiàn),在TDP中也是如此。而Nagle算法是要求一個TCP(TDP也是如此)連接上最多只能有一個未被確認的未完成的報文段,在該報文段的確認到達之前不能發(fā)送其他的報文段。相反,TCP(TDP也是如此)在這個時候收集這些報文段,關(guān)在確認到來時合并作為一個報文段發(fā)送出去。Nagle算法對于處理應用程序產(chǎn)生大量小報文段的情況,有利于避免網(wǎng)絡中由于發(fā)送太多的包而過載(這便是發(fā)送端的糊涂窗口綜合癥,關(guān)于糊涂窗口綜合癥在下文將做更詳細描述)。
             Nagle算法適用于產(chǎn)生大量小報文段的情況,但有時我們需要關(guān)閉Nagle算法。一個典型的例子是X窗口系統(tǒng)服務器:小消息(鼠標移動)必須無時延地發(fā)送,以便為進行某種操作的交互用戶提供實時的反饋。
             默認的TDP實現(xiàn)中Nagle算法是關(guān)閉的,用戶程序可以設(shè)置打開它。
             
             4.窗口大小通告與滑動窗口
             
             雙方接收模塊需要依據(jù)各自的緩沖區(qū)大小,相互通告還能接受對方數(shù)據(jù)的尺寸。雙方發(fā)送模塊則必須根據(jù)對方通告的接收窗口大小,進行數(shù)據(jù)發(fā)送。這種機制稱之謂滑動窗口,它是TDP接收方的流量控制方法。它允許發(fā)送方在停止并等待確認前可以連續(xù)發(fā)送多個分組(依據(jù)滑動窗口的大小),由于發(fā)送方不必每發(fā)一個分組就停下來等待確認,因此可以加速數(shù)據(jù)的傳輸。
             參照《TCP/IP詳解 卷一 20.3滑動窗口》一節(jié),滑動窗口在排序數(shù)據(jù)流上不時的向右移動,窗口兩個邊沿的相對運動增加或減少了窗口的大小,關(guān)于窗口邊沿的運動有三個術(shù)語:窗口合攏(當左邊沿向右邊沿靠近)、窗口張開(當右邊沿向右移動)、窗口收縮(當右邊沿向左移動)。RFC文檔強烈建議不要在實現(xiàn)當中出現(xiàn)窗口收縮的情況出現(xiàn),在我們的實現(xiàn)中也將不會出現(xiàn)。
             當遇到快的發(fā)送方與慢的接收方的情況時,接收方的窗口會很快被發(fā)送方的數(shù)據(jù)填滿,此時接收方將通告窗口大小為0,發(fā)送方則停止發(fā)送數(shù)據(jù)。直到接收方用戶程序取走數(shù)據(jù)后更新窗口大小,發(fā)送方可以繼續(xù)發(fā)送數(shù)據(jù);另外,因為ACK報文段有可能丟失,發(fā)送方可能沒有成功接收到更新的窗口大小,因此發(fā)送方將啟動一個堅持定時器,當堅持定時器超時,發(fā)送方將發(fā)送一個字節(jié)的數(shù)據(jù)到接收方,嘗試檢查窗口大小的更新。
             在Nagle算法中接到過糊涂窗口綜合癥,在這里要進一步進行描述。糊涂窗口綜合癥是指眾多少量數(shù)據(jù)的報文段將通過連接進行交換,而不是滿長度的報文段,這將導致連接占用過多帶寬,降低傳輸速率。糊涂窗口綜合癥產(chǎn)生是分兩端的,接收方可以通告一個小的窗口(而不是一直等到有大的窗口時才通告),發(fā)送方也可以發(fā)送少量的數(shù)據(jù)(而不是等待其他的數(shù)據(jù)以便發(fā)送一個大的報文段)。要以采用如下方法避免這一現(xiàn)象:
             1)接收方不通告小窗口。通常的算法是接收方不通告一個比當前窗口大的窗口(可以為0),除非窗口可以增加一個報文段大小(也就是將要接收的MSS)或者可以增加緩存空間的一半,不論實際有多少。
             2)發(fā)送方避免出現(xiàn)糊涂窗口綜合癥的措施是只有以下條件之一滿足時才發(fā)送數(shù)據(jù):(a)可以發(fā)送一個滿長度的報文段;(b)可以發(fā)送至少是接收方通告窗口大小一半的報文段;(c)可以發(fā)送任何數(shù)據(jù)并且不希望接收ACK(也就是說,我們沒有還未被確認的數(shù)據(jù))或者該連接上不能使用Nagle算法。
             
             5.PUSH標志
             
             PSUH標志的作用是發(fā)送方使用PUSH標志通知接收方將所收到的數(shù)據(jù)全部提交給接收進程。在TDP實現(xiàn)中,用戶程序并不需要關(guān)心PUSH標志。因為TDP實現(xiàn)從不將接收到的數(shù)據(jù)推遲交付給用戶程序,因此這個標志在TDP的實現(xiàn)中是被忽略的。
             
            五、TDP超時與重傳
             
             1.帶寬時延乘積與擁塞
             
             每個網(wǎng)絡通道都有一定的容量,可以計算通道的容量大小:
             Capacity(bit) = bandwidth(b/s) * round-trip time(s)
             這個值一般稱之為帶寬時延乘積。這個值依賴于網(wǎng)絡速度和兩端的RTT,可以有很大的變動。不論是帶寬還是時延均會影響發(fā)送方與接收方之間通路的容量。
             當數(shù)據(jù)到達一個大的網(wǎng)絡通道并向一個小的網(wǎng)絡通道發(fā)送,將發(fā)生擁塞現(xiàn)象。另外當多個輸入流到達一個路由器,而路由器的輸出流小于這些輸入流的總和時也會發(fā)生擁塞。TDP超時與重傳機制剛采用TCP的擁塞控制算法來進行發(fā)送端的流量控制。
             
             2.往返時間與重傳超時時間測量
             
             超時與重傳中最重要的部分就是對一個給定連接的往返時間(RTT)的測量。由于路由器和網(wǎng)絡流量均會發(fā)生變化,因此一般認為RTT可能經(jīng)常會發(fā)生變化,TDP應該跟蹤這些變化并相應地改變相應的超時時間。
             首先是必須測量在發(fā)送一個帶有特別序號的字節(jié)和接收到包含字節(jié)的確認之間的RTT。由于數(shù)據(jù)報文段與ACK之間通常沒有一一對應的關(guān)系,如下圖(摘自《TCP/IP詳解 卷一》圖20.1)中,這意味著發(fā)送方可以測量到的一個RTT,是在發(fā)送報文段4和接收報文段7之間的時間,用M表示所測量到的RTT。
             根據(jù)[Jacobson 1988]描述(見《TCP/IP詳解 卷一》參考文獻),用A表示被平滑的RTT(均值估計器),用D表示被平滑的均值偏差,用Err表示剛得到的測量結(jié)果M與當前RTT估計器之差,則可以計算下一個超時重傳時間(用RTO表示下一個超時重傳時間)。
             A = 0 (未進行測量往返時間之前,A的初始值)
             D = 3 (未進行測量往返時間之前,D的初始值)
             RTO = A + 2D = 6 (未進行測量往返時間之前,RTO的初始值)
             A = M + 0.5 (第一次測量到往返時間結(jié)果,對RTT估計器計算初始值)
             D = A / 2 (第一次測量到往返時間結(jié)果,對均值偏差D計算初始值)
             RTO = A + 4D (第一次測量到往返時間結(jié)果,對均值偏差RTO計算初始值)
             之后的計算方法如下:
             Err = M – A
             A <- A + gErr
             D <- D + h(|Err| - D)
             RTO = A + 4D
             其中g(shù)是常量增量,取值為1/8(0.125);h也是常量增量,取值為1/4(0.25)。
             
             
             
             Karn算法:Karn算法是解決所謂的重傳多義性問題的。[Karn and Partridge 1987]規(guī)定(見《TCP/IP詳解 卷一》參考文獻),當一個超時和重傳發(fā)生時,在重傳數(shù)據(jù)的確認最后到達之前,不能更新RTT估計器,因為我們并不知道ACK對應哪次傳輸(也許第一次傳輸被延遲而并沒有被丟棄,也有可能是第一次傳輸?shù)腁CK被延遲丟棄)。并且,由于數(shù)據(jù)被重傳,RTO已經(jīng)得到了一個指數(shù)退避,我們在下一次傳輸時使用這個退避后的RTO。對一個沒有被重傳的報文段而言,除非收到了一個確認,否則不要計算新的RTO。
             在任何時候?qū)γ總€連接并行僅測量一次RTT值,在發(fā)送一個報文段時,如果給定連接的定時器已經(jīng)被使用,則該報文段不被計時,反之如果給定連接的定時器未被使用,則開始計時以測量RTT值。即并非每個發(fā)出報文段都進行測量RTT值,同一時間段里只能有一個RTT值測量行為進行,不會并行進行多個RTT值測量。
             
             3.慢啟動
             
             如果發(fā)送方一開始便向網(wǎng)絡發(fā)送多個報文段,直至達到接收方通告窗口大小為止。當發(fā)送方與接收方在同一局域網(wǎng)時,這種方式是可以的。但如果在發(fā)送方與接收方之間存在多個路由器和速率較慢的鏈路時,就可能出現(xiàn)問題。一些中間路由器必須緩存分組,并有可能耗盡存儲器的空間,將來得降低TCP連接的吞吐量。于是需要一種叫“慢啟動”的擁塞控制算法。
             慢啟動為發(fā)送方增加一個擁塞窗口,記為cwnd,當與另一個網(wǎng)絡的主機建立連接時,擁塞窗口被初始化為1個報文段。每收到一個ACK,擁塞窗口就增加一個報文段(cwnd以字節(jié)為單位,但慢啟動以報文段大小為單位進行增加)。發(fā)送方取擁塞窗口與通告窗口中的最小值作為發(fā)送上限。擁塞窗口是發(fā)送方使用的流量控制,而通告窗口是接收方使用的流量控制。
             發(fā)送方開始時發(fā)送一個報文段,然后等待ACK。當收到該ACK時,擁塞窗口從1增加到2,即可以發(fā)送兩個報文段。當收到這兩個報文段的ACK時,擁塞窗口就增加為4。這是一種指數(shù)增加的關(guān)系。
             
             4.擁塞避免
             
             慢啟動算法增加擁塞窗口大小到某些點上可能達到了互聯(lián)網(wǎng)的容量,于是中間路由器開始丟棄分組。這就通知發(fā)送方它的擁塞窗口開得太大。擁塞避免算法是一種處理丟失分組的方法。該算法假定由于分組受到損壞引起的丟失是非常少的(遠小于1%),因此分組丟失就意味著在源主機和目標主機之間的某處網(wǎng)絡上發(fā)生了擁塞。有兩種分組丟失的指示:發(fā)生超時和接收到重復的確認。擁塞避免算法與慢啟動算法是兩個獨立的算法,但實際中這兩個算法通常在一起實現(xiàn)。
             擁塞避免算法和慢啟動算法需要對每個連接維持兩個變量:一個擁塞窗口cwnd和一個慢啟動門限ssthresh。算法的工作過程如下:
             1) 對一個給定的連接,初始化cwnd為1個報文段,ssthresh為65535個字節(jié)。
             2) TCP輸出例程的輸出不能超過cwnd和接收方通告窗口的大小。擁塞避免是發(fā)送方使用的流量控制,而通告窗口則是接收方進行的流量控制。前者是發(fā)送方感受到的網(wǎng)絡擁塞的估計,而后者則與接收方在該連接上的可用緩存大小有關(guān)。
             3) 當擁塞發(fā)生時(超時或收到重復確認),ssthresh被設(shè)置為當前窗口大小的一半(cwnd和接收方通告窗口大小的最小值,但最少為2個報文段)。此外,如果是超時引起了擁塞,則cwnd被設(shè)置為1個報文段(這就是慢啟動)。
             4) 當新的數(shù)據(jù)被對方確認時,就增加cwnd,但增加的方法依賴于我們是否正在進行慢啟動或擁塞避免。如果cwnd小于或等于ssthresh,則正在進行慢啟動,否則正在進行擁塞避免。慢啟動一直持續(xù)到我們回到當擁塞發(fā)生時所處位置的半時候才停止(因為我們記錄了在步驟2中給我們制造麻煩的窗口大小的一半),然后轉(zhuǎn)為執(zhí)行擁塞避免。
             慢啟動算法初始設(shè)置cwnd為1個報文段,此后每收到一個確認就加1。這會使窗口按指數(shù)方式增長:發(fā)送1個報文段,然后是2個,接著是4個……。擁塞避免算法要求每次收到一個確認時將cwnd增加1/cwnd。與慢啟動的指數(shù)增加比起來,這是一種加性增長。我們希望在一個往返時間內(nèi)最多為cwnd增加1個報文段(不管在這個RT T中收到了多少個ACK),然而慢啟動將根據(jù)這個往返時間中所收到的確認的個數(shù)增加cwnd。
             處于擁塞避免狀態(tài)時,擁塞窗口的計算公式如下(引公式參照BSD的實現(xiàn),segsize/8的值是一個匹配補充量,不在算法描述當中):
             cwnd <- cwnd + segsize * segsize / cwnd + segsize / 8
             
             5.快速重傳與快速恢復
             
             由于我們不知道一個重復的ACK是由一個丟失的報文段引起的,還是由于僅僅出現(xiàn)了幾個報文段的重新排序,因此我們等待少量重復的ACK到來。假如這只是一些報文段的重新排序,則在重新排序的報文段被處理并產(chǎn)生一個新的ACK之前,只可能產(chǎn)生1 ~ 2個重復的ACK。如果一連串收到3個或3個以上的重復ACK,就非常可能是一個報文段丟失了。于是我們就重傳丟失的數(shù)據(jù)報文段,而無需等待超時定時器溢出。這就是快速重傳算法。接下來執(zhí)行的不是慢啟動算法而是擁塞避免算法。這就是快速恢復算法。
             這個算法通常按如下過程進行實現(xiàn):
             1) 當收到第3個重復的ACK時,將ssthresh設(shè)置為當前擁塞窗口cwnd的一半。重傳丟失的報文段。設(shè)置cwnd為ssthresh加上3倍的報文段大小。
             2) 每次收到另一個重復的ACK時,cwnd增加1個報文段大小并發(fā)送1個分組(如果新的cwnd允許發(fā)送)。
             3) 當下一個確認新數(shù)據(jù)的ACK到達時,設(shè)置cwnd為ssthresh(在第1步中設(shè)置的值)。這個ACK應該是在進行重傳后的一個往返時間內(nèi)對步驟1中重傳的確認。另外,這個ACK也應該是對丟失的分組和收到的第1個重復的A C K之間的所有中間報文段的確認。這一步采用的是擁塞避免,因為當分組丟失時我們將當前的速率減半。
             
            六、代理socks5支持
             
             參照RFC1928、RFC1929,在TDP實現(xiàn)中,支持匿名通過socks5代理以及用戶名/密碼驗證方式通過socks5代理。
             由于socks5代理是工作于運輸層上,因此連接當中對IP層選項的設(shè)置都將沒有效果。socks5代理起到的作用只是應用數(shù)據(jù)的轉(zhuǎn)發(fā),但這已經(jīng)基本上能支持大部分用戶程序的應用需求。在使用socks5代理進行工作中,路徑MTU的發(fā)現(xiàn)機制,將無法有效工作,此時MSS默認為536(MTU默認為576),用戶程序可以修改使用的MSS值。
             
            七、安全考慮
             
             TDP協(xié)議及算法方面并不對數(shù)據(jù)的安全性做任何考慮,用戶程序在傳輸數(shù)據(jù)時如果對安全性有要求,可以自行在應用數(shù)據(jù)層做相應的工作。但TDP實現(xiàn)中,會提供一個簡單的AES256位加解密方法,提供給用戶程序使用。用戶程序可以調(diào)用該加解密方法,對數(shù)據(jù)進行加密然后再通過網(wǎng)絡進行發(fā)送,接收時將加密數(shù)據(jù)流進行解密再將會用戶程序數(shù)據(jù)邏輯處理模塊進行處理。
             
            八、定時器
             
             如BSD的TCP實現(xiàn)類似,TDP也為每條連接建立了六個定時器,簡要介紹如下:
             1)“連接建立”定時器,在發(fā)送SYN報文段建立一條新的連接時啟動。如果沒有在75秒內(nèi)收到響應,連接建立將中止。
             2)“重傳”定時器,在發(fā)送數(shù)據(jù)時設(shè)定。如果定時器已超時而對端的確認還未到達,將重傳數(shù)據(jù)。重傳定時器的值是動態(tài)計算的,取決來RTT與該報文段被重傳的次數(shù)。
             3)“延遲ACK”定時器,收到必須確認但無需馬上發(fā)出確認的數(shù)據(jù)時設(shè)定。等待200ms后發(fā)送確認響應。如果,在這200ms內(nèi),有數(shù)據(jù)要在該連接上發(fā)送,延遲的ACK響應就可隨數(shù)據(jù)一起發(fā)送回對端,稱為捎帶確認。
             4)“堅持”定時器,在連接對端通告接收窗口為0,阻止繼續(xù)發(fā)送數(shù)據(jù)時設(shè)定。堅持定時器在超時后向?qū)Χ税l(fā)送1字節(jié)的數(shù)據(jù),判定對端接收窗口是否已經(jīng)打開。堅持定時器的值是動態(tài)的計算的,取決于RTT值,在5秒與60秒之間取值。
             5)“保活”定時器。TDP連接在一定時間段內(nèi)如果沒有數(shù)據(jù)交互的話,將主動發(fā)送保活LIV報文段。即當“保活”定時器超時,說明沒有數(shù)據(jù)交互,則發(fā)送保活數(shù)據(jù)包。保活定時器默認時間為2分鐘,用戶程序可以進行設(shè)置。
             6)TIME_WAIT定時器,也可稱為2MSL定時器(實現(xiàn)中,一個MSL為1分鐘)。當連接狀態(tài)轉(zhuǎn)移到TIME_WAIT時,即連接主動關(guān)閉時,定時器啟動。
             
            九、開發(fā)接口
             
             使用TDP進行網(wǎng)絡程序開發(fā)是非常容易的,它的開發(fā)接口(API)與socket API是非常相似的,尤其是對應功能的函數(shù)名稱都是一致的,需要注意的是TDP的所有API都處于名稱空間TDP之下。開發(fā)接口見下表:
             
            函數(shù) 描述 
            TDP::accept 接受一個鏈接 
            TDP::bind 綁定本地地址到一個TDP::SOCKET句柄 
            TDP::cleanup 清除TDP全局資源,一個進程中只需要調(diào)用一次 
            TDP::close 關(guān)閉已打開的TDP::SOCKET句柄,并關(guān)閉連接 
            TDP::connect 連接到服務器端 
            TDP::getlasterror 獲得TDP最后的一個錯誤 
            TDP::getpeername 讀取連接的對端的地址信息 
            TDP::getsockname 讀取連接的本地的地址信息 
            TDP::getsockopt 讀取TDP的選項信息 
            TDP::listen 等待客戶端來連接 
            TDP::recv 接收數(shù)據(jù) 
            TDP::select 等待集合中的TDP SOCKET改變狀態(tài) 
            TDP::send 發(fā)送數(shù)據(jù) 
            TDP::setsockopt 修改TDP的選項信息 
            TDP::shutdown 指定關(guān)閉連接上雙工通信的部分或全部 
            TDP::socket 創(chuàng)建一個TDP SOCKET 
            TDP::startup 初始化TDP全局信息,一個進程中只需要調(diào)用一次 
             
            十、作者簡介
             
            黃洪波,男,1979年11月20日出生;
            2002.6年畢業(yè)于江西農(nóng)業(yè)大學計算機與信息工程學院;
            2002.6-2003.7年工作于先鋒軟件股份有限公司,從事電子政務及企業(yè)信息化研究與開發(fā);
            2003.7-2006.6年工作于金山軟件股份有限公司金山毒霸事業(yè)部,從事企業(yè)信息安全領(lǐng)域研發(fā)工作,專注于網(wǎng)絡應用技術(shù)及安全的研究;
             2006年6月中旬至今,成為軟件自由人,目前從事TDP(TCP-over-UDP library)及項目PlumBlossom研發(fā)。 

            posted on 2009-03-17 22:05 大龍 閱讀(9739) 評論(14)  編輯 收藏 引用

            評論

            # re: (TCP-over-UDP library):基于UDP協(xié)議之上實現(xiàn)通用、可靠、高效的TCP協(xié)議 ---------- 轉(zhuǎn) 2009-05-25 14:04 freemel

            你的這種模式, 除了能穿越防火墻外, 性能上比TCP高多少? 感覺不如直接用TCP啊  回復  更多評論   

            # re: (TCP-over-UDP library):基于UDP協(xié)議之上實現(xiàn)通用、可靠、高效的TCP協(xié)議 ---------- 轉(zhuǎn) 2010-05-28 00:07 VALARIELara

            My essays writing skills are poor. So, to order literary essays using some <a href="http://www.bestwritingservice.com">essay writing</a> service supposes to be the best way in this case.   回復  更多評論   

            # re: (TCP-over-UDP library):基于UDP協(xié)議之上實現(xiàn)通用、可靠、高效的TCP協(xié)議 ---------- 轉(zhuǎn) 2010-06-15 19:12 buy resume

            Yeah doubtless very
            crucial for the lector it was pleasant to read about this post! If you need to get a great job firstofall you need resume services. Study and don't forget - if you have to work and study at the same time, there areexperts who are ready to benefit you with your resume when you under time encumbrance and looking for a great job.  回復  更多評論   

            # re: (TCP-over-UDP library):基于UDP協(xié)議之上實現(xiàn)通用、可靠、高效的TCP協(xié)議 ---------- 轉(zhuǎn) 2010-06-18 22:38 essay example

            Do you remember that the essay writing service will be able to create A+ analysis term papers, hence don't miss your opportunity, purchase customized essay.   回復  更多評論   

            # re: (TCP-over-UDP library):基于UDP協(xié)議之上實現(xiàn)通用、可靠、高效的TCP協(xié)議 ---------- 轉(zhuǎn) 2010-09-23 10:01 jangsong

            tcp over udp  回復  更多評論   

            # re: (TCP-over-UDP library):基于UDP協(xié)議之上實現(xiàn)通用、可靠、高效的TCP協(xié)議 ---------- 轉(zhuǎn) 2012-12-26 17:33 shuiren

            @freemel
            搞笑,你覺得會比tcp快?
            想都不用想,肯定會慢  回復  更多評論   

            # re: (TCP-over-UDP library):基于UDP協(xié)議之上實現(xiàn)通用、可靠、高效的TCP協(xié)議 ---------- 轉(zhuǎn) 2012-12-26 17:39 shuiren

            就是在udp上在加一層,算法上和tcp一模一樣,把tcp中原來ip層干的事情由udp層做了而已。相比tcp協(xié)議直接使用ip層的數(shù)據(jù),既然加了個層,必然會變慢。
            這個網(wǎng)絡層結(jié)構(gòu)看起來會很詭異。本人確實不知道nat穿透有多少人需要,udp在做穿透時比tcp又有多大優(yōu)勢,但真心覺得,這個東東性價比不高。  回復  更多評論   

            # re: (TCP-over-UDP library):基于UDP協(xié)議之上實現(xiàn)通用、可靠、高效的TCP協(xié)議 ---------- 轉(zhuǎn) 2012-12-26 17:44 shuiren

            擼主有這時間不如直接在ip層上實現(xiàn)一個和tcp udp平級而不同于tcp的另一套可靠傳輸協(xié)議得了,并編譯好驅(qū)動去發(fā)布,豈不靠譜多了,還能順帶搞搞方校長的墻,功德無量  回復  更多評論   

            # re: (TCP-over-UDP library):基于UDP協(xié)議之上實現(xiàn)通用、可靠、高效的TCP協(xié)議 ---------- 轉(zhuǎn) 2013-10-23 23:49 shui

            我個人認為這是應用場景不同,采用udp的,比如流媒體的視頻,是可以丟包了,這時候,如果是tcp,壓力就比較大了!  回復  更多評論   

            # re: (TCP-over-UDP library):基于UDP協(xié)議之上實現(xiàn)通用、可靠、高效的TCP協(xié)議 ---------- 轉(zhuǎn) 2015-12-21 13:11 pcplayer

            你這個思路,我在04年實現(xiàn)過。當時只花了一周的時間就寫出來了,工作很穩(wěn)定,當然,因為只花了一周,沒去做優(yōu)化,通訊效率不高。

            看到有人留言說這樣做性價比不高,沒什么用。這些人都是不懂具體需求的。  回復  更多評論   

            人人狠狠综合久久88成人| 久久久这里有精品中文字幕| 久久久久久精品无码人妻| 99久久国产精品免费一区二区| 久久久久久久久无码精品亚洲日韩| 国产成人久久激情91| 无码8090精品久久一区| 久久综合精品国产二区无码| 狠狠人妻久久久久久综合蜜桃| yy6080久久| 久久精品国产亚洲5555| 久久久精品2019免费观看| 国产精品99久久久久久猫咪 | 国内精品久久久久久久97牛牛| 久久国产精品久久国产精品| 国产一区二区久久久| 91精品久久久久久无码| 久久人人爽人人爽人人片av高请| 久久91精品综合国产首页| 国产午夜精品久久久久免费视| 国内精品久久久久影院老司| 国产女人aaa级久久久级| 97久久综合精品久久久综合| 久久精品卫校国产小美女| 久久国产综合精品五月天| 久久不射电影网| 狠狠狠色丁香婷婷综合久久五月| 久久精品国产99久久久| 久久久久亚洲AV成人网人人网站 | 久久久久久亚洲Av无码精品专口| 久久久午夜精品福利内容| 久久噜噜久久久精品66| 久久久久久毛片免费看| 国产2021久久精品| 国产精品日韩深夜福利久久| 精品久久久久久无码中文野结衣| 91久久婷婷国产综合精品青草 | 久久久高清免费视频| 欧美亚洲国产精品久久| 亚洲AV日韩AV天堂久久| 久久精品国产亚洲AV麻豆网站|