關於UDP可靠傳輸的一些思考和總結

2021-10-04 20:17:03 字數 4314 閱讀 7386

有空來論壇走走,發現討論udp可靠傳輸又熱了起來,有人認為udp高效率,有人認為udp丟包重傳機制容易控制,還有朋友搞極限測試,當然也有人推銷自己的東西,這裡寫一點我個人的看法。

udp可靠傳輸其實非常非常的簡單,我最開始接觸udp可靠傳輸大約是在2023年,因為那時候開發ftpanywhere,由於路由的對映和閘道器nat處理方面,認為udp具有天生優勢,因此開始編寫自己的udp可靠傳輸協議,好象那個時候已經有了udt,我也下了源**看了下,不過很快就看不下去了,因為它用了定時器,加上跨平台處理,導致它的**,反正我看著很亂,理不出乙個完整的邏輯圖。但是原理和tcp的基本一樣,並沒有什麼特殊的。後來我寫了我自己的第乙個udp可靠傳輸類,qtudp,這個是最簡單的,也就是和tcp一樣,實現2點之間的傳輸,並不是我現在寫的多點之間無中心p2p傳輸,效率很高,但是當時的編碼我還沒有養成現在的習慣,用了大量的dword之類的資料定義,包括包的定義,從現在角度看,不及格,不過至少它可以實用,並整合到了ftpanywhere軟體中,在除錯和執行過程中,慢慢的統計和發現udp包的傳輸中,最影響效能的部分以及其他一些細節,後來的ut 1.x多點傳輸協議就是在qtudp基礎上開發的,在到現在 ut 2.x , phoenix 2.x,實現了幾個跨越。

請相信,可靠udp傳輸從來都不是高效率可靠傳輸的代名詞,影響傳輸效率的最重要因素在於,sendto函式,每次只能投遞乙個mtu長度的包,頻繁的系統呼叫極大的影響了極限效能,也許你會說,udp預設可以達到64kb,你可以投遞大包,是的,可以投遞,但是由於網路上mtu裝置的限制,大包會被拆成小包,如果你定義乙個包大於mtu,那麼當其中任何乙個小包發生丟包的時候,會導致整個包需要重傳,這個開銷非常巨大,特別是在internet上,而採用mtu大小限制內的包進行傳輸,丟失乙個,只需要重傳乙個,開銷小的多。udp可靠傳輸的自定義校驗是另外乙個限制,為了避免偽造的udp包,我們需要在我們自己的可靠udp包中加入自定義的校驗,這個校驗方法也直接影響到效能,最快的是直接套用crc32校驗,由於目前cpu指令集對這個計算進行了優化,因此它的計算速度幾乎是最快的,但是代價是,人家要破解或者偽造你的udp包也很容易,因為演算法是透明的,以前暴出tcp偽造漏洞也是這樣,由於它的包組成是透明公開,唯一有保密性的是序列號,結果有些系統初始序列號存在規律,結果就導致了安全問題。最後,傳送和接收,由於是在應用層進行[無論你是採用api epoll select overlap io,最終的執行都是在應用層],這個傳送-確認過程中,由於應用層不是象tcp/ip協議棧那樣在核心態執行,因此可能有延遲,不過,目前的cpu核心數量和頻率,這個影響在工業應用[internet 等]已經幾乎可以忽略,唯一產生影響是在進行本機極限效能測試中。tcp的效率要高過udp可靠傳輸,因為它的send函式,幾乎每次都可以拷貝幾十kb,當然你可以將緩衝調整的很大,例如幾百kb或者幾mb,但是預設情況下的幾十kb足夠了,想當於幾十次呼叫udp sendto , 而tcp只需要呼叫一次,其次,tcp的包處理是在核心態進行,確認也是核心態,這就足以與應用層的udp可靠傳輸拉開距離,更別說硬體層的優化了. 那麼,你可能會認為,為什麼書上說udp效能好呢?其實這是針對不可靠udp傳輸,並且是內網 大包,例如

char buffs[32*1024];

memset(buffs,0,32*1024);

sendto(s , buffs,32*1024,.... 發射後不管,無論是否丟包

象這樣發包,效率才會超過tcp,不過,主要就是包頭大小的差距.

關於udp的穿透能力,也就是傳說中的打洞,這根本是個偽命題,有人還在那裡搞什麼測試說打通了4種 nat 模型, 你認為可能嗎? 還有人用猜埠的方法進行打洞,我了個去,工業上能這麼用? udp的穿透其實完全取決於路由[閘道器]的配置,國產的家用或者soho針對p2p進行過調整,但是你用cisco 等專業的大型裝置進行打洞看看,為了保護使用者的安全,一般管理員都設定了高安全非透明,通常,就算是內部同一臺電腦,同乙個udp埠,傳送給不同的目標ip資料報,路由都會隨機重新分配乙個埠,打洞根本不可能成功的. 所以,如果你為了nat處理而使用udp,建議你還是放棄吧,直接使用tcp+upnp就行.

關於udp可靠傳輸的效能,有人說使用epoll , overlap io 等,效率高於使用select模型, 我可以根據我的這幾年開發的經歷和測試結果告訴你,在校驗模式,投遞模式以及資料處理邏輯相同的情況下,多核心cpu平台下,本機效率差距不超過1%,而如果使用在internet上,效率差距無限接近0,現在是cpu過剩的年代,linux  windows的排程下,如果沒有核心態運算,那麼就會從等待的執行緒中挑選乙個,你不要以為從核心態切換到使用者態是不需要開銷的,這個開銷同樣很大,頻繁的排程同樣影響效能,雖然不算在你的**中而算在系統開銷中. 當然,如果你需要在linux系統中同時執行apache等web服務,那效率差距會比較明顯,因為程序和執行緒太多,得不到第一時間的排程.

關於udp可靠傳輸下緩衝大小,說實話,我是第一次見識,最簡單的點對點 udp可靠傳輸,有人開了上百kb的緩衝,緩衝是個好東西,通常,緩衝越大,效率越高,因為一次投遞的包數量多,io效能就高,但是,這在internet上是不提倡的,這種實現我不知道是否經過嚴格的網路丟包和負載測試,在有家用路由小頻寬上傳模式下,如果有多人或者多個網路程式使用頻寬,這個延遲引數變動非常頻繁,不必要的重傳率會非常高,最簡單的測試方法,找個銅包鋁網線,使用1 1對應的非標準接頭法,一頭接電腦,一頭接路由,然後與internet上遠端進行測試,估計這個丟包重傳的概率會高的嚇人.

udp可靠傳輸比tcp的慢啟動好?我想不一定,還是我上面那個網線做測試,如果採用快速啟動,在丟包嚴重的網路環境下,頻寬浪費太離譜了,我調整我自己的udp可靠傳輸啟動方法好多次,越來越覺得tcp的慢啟動是非常有道理的,雖然恢復的慢,但是,它因為錯誤重傳而產生頻寬的浪費是非常小的. 當然,如果考慮到效能,還是可以適當調整的快點.

關於udp可靠傳輸的檔案傳輸效率,這是個偽命題,這個極限是硬體本身造成的,首先,正常的udp可靠傳輸效率肯定高於普通硬碟的讀寫盤速度,即使用memory map 技術對檔案執行加速,還是跟不上udp本身的速度,其次,檔案傳輸協議會影響到傳輸效率,最快的模式是什麼? 就是直接傳送檔案從開始到結尾,和流 [ftp資料連線 http]一樣,這是最快的,但是通常,為了避免資料差錯,會對檔案傳輸內容進行分塊傳輸,並加入校驗.這就影響到了傳輸效率. 你說一輛公共汽車是從起點到終點直達快?還是一站站的停過去快?很明顯,第乙個假設脫離實際的.

關於udp可靠傳輸和cpu的關係,有嗎?肯定有,但是在普通應用下,基本沒影響,只有在追求極限,例如本機測試,2g+光釺網路等,才會有明顯的影響,可問題是,如果你的伺服器[電腦]接入的是2g+光釺,你這伺服器得什麼硬體配置? 在一般應用下,cpu和記憶體開銷以及錯誤的丟包重傳才是第一位的. 如果乙個udp可靠傳輸,100mbps網路下,必須要intel piii 1ghz以上,那在這個基礎上開發出來的應用可能比現在的電腦遊戲還離譜了.  如果不是多對多[因為這個邏輯比普通點對點udp可靠傳輸複雜的太多],普通的點對點udp可靠傳輸, 給幾個以前的測試資料, qtudp ,環境是pentium m 1.7g[單核心], ati xpress主機板 768m ddr2 533[單通道] , 本機器模擬傳輸當時測試的資料大約在 78mb/s , mtu=1380 , 緩衝是 17 * mtu.  , cpu開銷大約是75%, 如果使用目前雙核心,估計可以翻倍. 你可能會覺得這個數字太低,但是請注意當時的硬體環境,這個速度已經超過udt好多好多了. 最基本的點對點udp可靠傳輸,標準crc32校驗,以目前的硬體環境, i74核心, ddr3 1600 , 加上我們的一種特殊包處理技術,本機器udp小包[1400]可靠傳輸的極限大約在270mb/s,如果還要提公升,估計只能和ms 的iis一樣,編寫網路驅動了,但是x86處理器和記憶體速度始終在提公升,說不定明天主頻直接翻倍了...

其實,我轉向udp可靠傳輸的乙個非常重要原因,是ipv6取消了傳輸中ip層的資料校驗,這導致tcp層完全負擔起了資料校驗任務,tcp資料是否還象ipv4下那麼可靠,需要加個問號了,雖然ip層本身的差錯率非常低,但是取消掉校驗,直接帶來的風險到底有多大,並沒有經過實踐的評估,靠ipv6實驗網路得出的是理論結果,也許有一天會出現一種突破性的ipv6 tcp偽造技術. 而如果採用udp可靠傳輸,由於udp本身有校驗,加上我們自己設計的校驗和序列號,這個可靠程度完全超過了ipv4 下的tcp,更別提ipv6下的tcp了.

udp可靠傳輸,其實非常簡單,只要你有tcp/ip的基礎,最簡單的點對點udp可靠傳輸是非常容易編寫的,無非就是封包,校驗,傳送,確認,重新組包,介面可以模仿tcp的幾個函式,這其中的乙個難點是,判斷是否需要重發,這需要根據以前包的確認時間來推導本包,如果你不希望那麼複雜,也可以,經驗數字 [不適合網通到電信], 第一次的重傳時間 750 ms , 第二次是 1600 , 以後每次都是 2000 , 雖然不科學,但是用這個延遲數字,可以保證你足夠的傳輸效率[即使存在小概率丟包],也不會產生大量的重傳,當然最好的方法是從之前包的延遲來推導. 

總之,udp可靠傳輸沒那麼複雜和神秘,它非常簡單,而且,它的效率也沒有各位想象中的那麼高,可能會讓各位失望,但是,它很可愛,你可以隨意的塑造你自己的包,實現各種擴充套件,其中的取捨完全在於聰明的你.

udp可靠傳輸的一種

udp廣播示例 unix套接字可靠傳輸 只能客戶端到服務端,服務端無法sendto 接收端recvfrom介紹 本地程序間通訊方式的一種,unix可靠傳輸 接收端rec.c include include see notes include include include include inclu...

關於SpringIOC的一些思考

ioc是 依賴倒置原則 的乙個特例,說其是特例,就是說其具有 依賴倒置原則 的性質。依賴倒置原則強調的兩點是 上層模組和下次模組都依賴於抽象,二者之間通過這種抽象的東西聯絡在一起 具體可以依賴於抽象,而抽象不能依賴於具體。我認為spring提倡的 基於介面程式設計 就是為了遵循 依賴倒置原則 其中所...

關於sizeof 的一些思考

今天面試被問到sizeof,回來整理一下。1 定義 sizeof是c c 中的乙個操作符 operator 作用就是返回乙個物件或者型別所佔的記憶體位元組數。msdn上的解釋為 the sizeof keyword gives the amount of storage,in bytes,assoc...