我已經用 C 構建了一個 UDP 服務器,我對此有幾個問題。
目標:
我有傳入的 TCP 流量,我需要將其作為 UDP 流量進一步發送。我自己的 UDP 服務器然后處理這個 UDP 資料。TCP 資料包的大小可能會有所不同。
細節:
在我的示例中,我有一個總共包含 2000 個位元組 ( 4 random bytes, 1995 'a' (0x61) bytes and the last byte being 'b' (0x62))的 TCP 資料包。
我的 UDP 服務器有一個緩沖區 ( recvfrom buffer),其大小大于 2000 位元組。我的 MTU 大小到處都是 1500。
我的服務器正在正確接收此資料包。在我的 UDP 服務器中,我可以看到接收到的資料包的長度為 2000,如果我檢查最后一個位元組buffer[1999],它會列印“b”(0x62),這是正確的。但是如果我打開,tcpdump -i eth0我只會看到一個 UDP 資料包:09:06:01.143207 IP 192.168.1.1.5472 > 192.168.1.2.9000: UDP, bad length 2004 > 1472. 使用該tcpdump -i eth0 -X命令,我看到了資料包的資料,但只有 ~1472 位元組,其中不包括“b”(0x62)位元組。
該ethtool -k eth0命令列印udp-fragmentation-offload: off.
所以我的問題是:
- 為什么我只看到一個資料包而不是兩個(分片的第 1 部分和第 2 部分)?
- 為什么我在 tcpdump 中看不到“b”(0x62)位元組?
- 在我的 C 服務器中,最好使用什么緩沖區大小?我現在在 65535 上有它,因為傳入的 TCP 資料包可以是任何大小。
- 如果大小超過 65535 位元組會發生什么,我是否必須在將 TCP 資料包作為 UDP 發送之前制定自己的分片方案?
uj5u.com熱心網友回復:
TCP 資料包的大小可能會有所不同。
雖然上面的句子沒有顯示代碼,但您的描述表明您對 TCP 的作業方式做出了錯誤的假設。
與UDP相反,TCP不是基于訊息的協議而是位元組流。這尤其意味著它不保證send發件人的單曲recv會與收件人的單曲相匹配。因此,即使send完成了 2000 個位元組,它仍然可能是第一個recv只獲得 1400 個位元組,而另一個recv將獲得其余的 - 無論一切是否一次都適合套接字緩沖區。
uj5u.com熱心網友回復:
好的,情況更復雜,因為它們從問題中出現,從您的評論中提取,有以下資訊可用:
- 一些客戶端通過 TCP 向服務器發送資料——兩者都不可修改。
- 然而,在兩者之間有一個防火墻,只允許通過 UDP 與服務器進行單向通信。
- 您現在打算實作一個代理,該代理由位于兩者之間的兩個服務器組成,并通過 UDP 傳輸 TCP 資料。
- 服務器無法向后回復也不會造成問題。
我個人的方法如下:
- 讓代理服務器完全不知道資料!讓出站接收器接受(
recv或recvfrom取決于單個或多個客戶端可用)尚未裝入 UDP 資料包的資料塊,并按原樣簡單地轉發它們。 - 應用一些方法來確保至少檢測到丟失的資料,更好的是可以重建丟失的資料。由于防火墻限制,確認或重新請求訊息是不可能的,但提高可靠性的唯一機會是通過冗余。
- 將最終目標服務器配置為僅偵聽環回。
- 讓入站代理通過 TCP 連接到目標服務器,只要沒有(不可恢復的)錯誤發生,就按原樣轉發任何傳入資料。
為了能夠檢測丟失的訊息,我至少會在發送的任何UDP 訊息前添加一個資料包計數器。如果兩個隨后的訊息沒有提供連續的計數器值,則中間的訊息已經丟失。
由于不可能進行反向通信,因此提高可靠性的唯一方法是無條件冗余,交換一些傳輸速率,例如通過多次發送每條訊息并忽略接收端多余的重復項。
一種更精細的方法可能會將冗余資料分布在多個資料包上,以便可以從剩余的資料包中重建丟失的資料——這可能類似于RAID 級別 5所做的。承認,你需要非常致力于嘗試......
最后一個問題是路由的樣子。UDP 無法保證資料包的接收順序與發送順序相同。如果確實只有一個修復路由從出站代理到入站代理通過防火墻可用,那么資料包不應該超過另一個 – 您可能仍然希望至少記錄到適當的檔案以監控入站 UDP 資料包,并在發生錯誤的情況下應用適當的意味著(緩沖資料包并在需要時重新排序)。
轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/388771.html
