2012-11-19 62 views
1

我正在重新實現一箇舊的網絡層庫,但是這次使用boost asio。我們的軟件是tcpip與第三方軟件對話。幾條消息在雙方表現都非常好,但有一種情況我誤解了:TCP數據包通常是否重新排序?

第三方一個接一個地發送兩個消息(msg A和B)(實際的短時間),但我只收到一部分消息A在tcp-packet 1中,並且消息A的結束和在tcp-packet 2中的整個消息B.(我用wireshark嗅探)。

我還沒有想到這種情況,我想知道它是否與tcp常見,如果我的圖層應該適應這種情況 - 或者我應該告訴第三方檢查他們在他們身邊做了什麼因爲我收到了不同數據包中的兩個消息。

+0

這是通過相同的套接字嗎? – Default

+0

你的意思是你永遠不會得到完整的信息A? – Default

+0

我使用相同的套接字是的,我收到完整的消息A,但分派到兩個數據包。所有的數據都在這裏。我的問題是與消息B,我沒有看到,因爲它是在同一個數據包中的消息一結束後。 –

回答

4

數據包可能被分段並且無法到達。接收它們的TCP堆棧應該緩存並重新排序它們,然後將數據作爲傳入流呈現給應用層。

我的問題是與消息B,我沒有看到,因爲它是在同一個數據包中的消息一結束後。

您不能依賴具有與數據包的一對一映射關係的「消息」:對於應用程序而言,TCP(不是UDP)看起來像是「流式」協議。

通過TCP發送的應用程序需要另一種方式來分離消息。有時候這是通過標記每封郵件的結尾來完成的。例如SMTP標誌着結束消息如下:

郵件消息的主體的傳輸與在這之後,通過線路傳送逐字線和 終止與一個 DATA命令啓動數據結束序列。這個序列由 組成一個新行(),一個句號(句號),然後是 另一個新行。由於消息正文可以包含一行僅包含句號 作爲文本的一部分,客戶端每發送一行 行就會發送兩個句點;相應地,服務器用一行代替行首的兩個句點的每個 序列。 這種逃避方法被稱爲點填充。

或者,該協議可能會在每條消息的開始處指定一個前綴,這將指示以字節爲單位的消息長度。

如果您正在對TCP協議棧進行編碼,那麼您將有權訪問TCP message header:「數據偏移」字段將告訴您每條消息有多長。

4

是的,這很常見。 TCP/IP是一種流媒體協議,您的「邏輯」數據包可能會分散在許多「物理」數據包中,因此客戶端負責組裝更高級別的數據包。另外,TCP/IP保證正確的順序,所以你不必擔心組裝亂序數據包。

3

你的問題與TCP完全無關。你的問題是你希望asio爲你做消息解析。它不,你必須執行它。

  • 如果您的郵件全部大小相同,請爲該大小執行異步讀取。
  • 如果它們的長度不同,請爲您的標頭大小執行異步讀取,分析標頭並根據標頭對其餘消息執行異步讀取。
  • 如果您的消息長度可變,大小未知但存在已定義的結束字符或序列,則必須將該剩餘字節保存在該結束序列之後,並將下一個讀取附加到該剩餘部分。