c ++ posix套接字recv功能

use*_*581 3 sockets recv

我有一个或许是一个非常有问题的问题,我环顾四周但是还没有看到直接的答案,我想我可以在这里得到一个快速的答案.在使用bsd套接字的简单TCP/IP客户端 - 服务器选择循环中,如果客户端发送两条同时到达服务器的消息,那么在服务器上调用recv会返回在缓冲区中捆绑在一起的两条消息,或者是不同的到达消息要单独阅读?

我问,因为我在一个环境中工作,我无法告诉客户端如何构建要发送的消息.通常recv报告读取12个字节,然后是915,然后是12个字节,然后是915,依此类推,这种交替的12到915模式......但有时它会报告927(即915 + 12).我以为客户端在将其发送到服务器之前将其中的一些信息捆绑在一起,或者在调用recv之前消息到达然后recv同时拉出所有挂起的字节.所以我想确保我理解recv的行为.我想也许在我的理解中我错过了一些东西,我希望有人能指出来,谢谢!

Rem*_*eau 7

TCP/IP是基于流的传输,而不是基于数据报的传输.在流中,send()和之间没有1对1的相关性recv().这仅适用于数据报.所以,你必须准备好处理多种可能性:

  1. 单个调用send()可能适合单个TCP数据包,只需一次调用即可完整读取recv().

  2. 单个调用send()可能跨越多个TCP数据包,需要多次调用recv()才能读取所有内容.

  3. 多次调用send()可以放在一个TCP数据包中,并通过一次调用完全读取recv().

  4. 多次调用send()可能跨越多个TCP数据包,并且需要recv()对每个数据包进行多次调用.

为了说明这一点,考虑发送两条消息 - send("hello", 5)send("world", 5).调用时,以下是一些可能的组合recv():

"hello" "world"
"hel" "lo" "world"
"helloworld"
"hel" "lo" "worl" "d"
"he" "llow" "or" "ld"
Run Code Online (Sandbox Code Playgroud)

明白了吗?这就是TCP/IP的工作原理.每个TCP/IP实现都必须考虑到这种情况.

为了正确接收数据,必须在逻辑消息之间进行明确的分离,而不是单独的呼叫send(),因为可能需要多次呼叫send()才能发送单个消息,而多次recv()呼叫要完全接收单个消息.因此,考虑到前面的示例,让我们在消息之间添加一个分隔符:

send("hello\n", 6);

send("world", 5);
send("\n", 1);
Run Code Online (Sandbox Code Playgroud)

在接收端,你可以recv()多次调用,直到\n收到一个角色,然后你会处理你收到的所有东西,直到那个角色.如果完成后仍有任何读取数据,请将其保存以供以后处理,然后recv()再次开始调用直到下一个\n字符,依此类推.

有时,不可能在消息之间放置一个唯一的字符(可能消息体允许使用所有字符,因此没有可用作分隔符的独特字符).在这种情况下,您需要在消息前面添加消息的长度,或者作为前面的整数,结构化的标题等.然后,您只recv()需要根据需要调用多次,直到您收到完整的整数/标题,然后调用recv()根据需要多次读取长度/标头指定的字节数.完成后,如果需要,保存所有剩余数据,并recv()再次开始调用以读取下一个消息长度/标题,依此类推.