• <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>

            大龍的博客

            常用鏈接

            統計

            最新評論

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

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

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

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

            評論

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

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

            # re: (TCP-over-UDP library):基于UDP協議之上實現通用、可靠、高效的TCP協議 ---------- 轉 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協議之上實現通用、可靠、高效的TCP協議 ---------- 轉 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協議之上實現通用、可靠、高效的TCP協議 ---------- 轉 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協議之上實現通用、可靠、高效的TCP協議 ---------- 轉 2010-09-23 10:01 jangsong

            tcp over udp  回復  更多評論   

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

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

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

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

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

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

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

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

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

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

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

            午夜精品久久久久久久无码| 久久亚洲春色中文字幕久久久 | 亚洲七七久久精品中文国产| 亚洲AⅤ优女AV综合久久久| 看全色黄大色大片免费久久久| 亚洲乱码日产精品a级毛片久久 | 91精品国产91久久| 天堂无码久久综合东京热| 中文字幕无码精品亚洲资源网久久| 狠狠色婷婷久久一区二区三区| 亚洲国产精品久久久久网站| 免费精品国产日韩热久久| 9999国产精品欧美久久久久久| 国产成人综合久久精品红| 9191精品国产免费久久| 无码人妻精品一区二区三区久久久| 国产精品99久久久久久猫咪| 久久久久高潮毛片免费全部播放| 欧美精品一区二区久久| 99热精品久久只有精品| 久久国产精品77777| 性高湖久久久久久久久| 久久久国产打桩机| 亚洲?V乱码久久精品蜜桃 | 久久久久高潮毛片免费全部播放| 一级a性色生活片久久无 | 国产精品久久新婚兰兰| 久久久久黑人强伦姧人妻| 26uuu久久五月天| 香蕉久久夜色精品国产小说| 91精品国产乱码久久久久久| 欧洲成人午夜精品无码区久久| 久久久久亚洲AV片无码下载蜜桃| 久久综合久久鬼色| 久久久久亚洲AV成人网人人网站 | 国内精品久久久久久中文字幕| 久久久精品国产sm调教网站| 欧美黑人激情性久久| 久久久久亚洲av无码专区喷水| 亚洲国产精品无码久久一线| 精品久久无码中文字幕|