首页 文章

c posix套接字recv功能

提问于
浏览
3

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

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

3 回答

  • 0

    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 字符,依此类推 .

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

  • 1

    它对于在单个recv调用中返回的两个消息肯定有效(请参阅Nagle's Algorithm) . TCP / IP保证顺序(消息中的字节不会混合) . 除了它们在单个调用中一起返回之外,单个消息还可能需要多次调用recv(尽管对于所描述的小数据包不太可能) .

  • 7

    你唯一可以指望的是字节的顺序 . 您不能指望它们如何被分区为recv调用 . 有时事情会在 endpoints 或沿途合并 . 事情也可以在途中被打破,因此独立到来 . 它听起来像你的发送者发送交替12和915,但你不能指望它 .

相关问题