TCP/IP是基於流的傳輸,而不是基於數據報的傳輸。在流中,send()
和recv()
之間不存在1對1的相關性。這僅適用於數據報。所以,你必須做好準備,以處理多種可能性:
到send()
單一呼叫可以容納在一個TCP數據包,並通過向recv()
單個呼叫在完整地閱讀。
對send()
的單個調用可能會跨越多個TCP數據包,並且需要多次調用recv()
才能讀取所有內容。
對send()
的多次調用可能適合單個TCP數據包,並可通過對recv()
的單次調用完全讀取。
對send()
的多次調用可能會跨越多個TCP數據包,並且需要對每個數據包多次調用recv()
。
爲了說明這一點,考慮兩個消息被髮送 - send("hello", 5)
和send("world", 5)
。撥打電話recv()
時,以下是幾種可能的組合:
"hello" "world"
"hel" "lo" "world"
"helloworld"
"hel" "lo" "worl" "d"
"he" "llow" "or" "ld"
獲得創意嗎?這就是TCP/IP的工作原理。每個TCP/IP實現都必須考慮到這種分割。
爲了正確地接收數據,必須有邏輯消息,而不是單個調用send()
之間的明確分離的,因爲它可能需要多次調用send()
發送單個消息,並且多個recv()
調用來接收單個信息完整。因此,以前面的例子進去,讓我們添加的消息之間的分隔符:
send("hello\n", 6);
send("world", 5);
send("\n", 1);
在接收端,你會叫recv()
多次都沒關係,直到收到\n
字符,然後你會處理你收到的所有東西都可以導致這個角色。如果在完成時剩餘任何讀取數據,請將其保存以備後續處理,並再次開始撥打recv()
,直到下一個\n
字符爲止,依此類推。
有時,不可能在消息之間放置一個唯一的字符(也許消息體允許使用所有字符,因此沒有可用作分隔符的獨特字符)。在這種情況下,您需要在郵件前加上郵件的長度,作爲前一個整數,結構化郵件頭等。然後,根據需要簡單地撥打recv()
,直到收到完整整數/標題,然後您根據需要調用recv()
多少次即可讀取與長度/標題指定的字節數相同的字節數。完成後,根據需要保存剩餘的數據,然後重新開始撥打recv()
以讀取下一個消息長度/標題,依此類推。
非常感謝您的詳細回覆,非常感謝。瞭解TCP/IP實現的基本細節有助於達成一致,並希望能夠幫助那些不瞭解的人。 – user1930581