recvfrom:等待完整消息(可变大小消息,线程)

Posted

技术标签:

【中文标题】recvfrom:等待完整消息(可变大小消息,线程)【英文标题】:Recvfrom: wait for full message (variable size message, thread) 【发布时间】:2017-10-18 09:35:20 【问题描述】:

我有一个 UDP 客户端,它以指定的速率向服务器发送消息。速率需要保持不变,因此我决定尝试在单独的线程中接收回复以避免阻塞或延迟recvfrom()。在接收之前是否有可能“等待”完整的消息?这样做的最佳策略是什么?

while (true)

    //std::this_thread::sleep_for(std::chrono::milliseconds(5000));
    if (recvfrom(threadSock, ReceiveBuf, BufLength, 0, 0, 0) == SOCKET_ERROR)
    
        printf("Thread Receive failed with error %ld\n", GetLastError());
        break;
    
    else
    
        printf("Reply received: %s\n\n", ReceiveBuf);
    
    memset(ReceiveBuf, '\0', BufLength);

以上是我的接收代码。目前,只有回复的前 8 个字符被读入缓冲区(缓冲区为 512 字节)。

如何等待完整的消息(请记住消息长度是可变的)。

这甚至可能吗?也许有更好的方法。

提前致谢。

编辑:我应该澄清一下打印件仅用于测试。它们不会出现在最终结果中,因为从线程打印会产生奇怪的内联打印。

【问题讨论】:

你怎么知道你只有 8 个字节?您不评估收到的字节数。 断点 :) 都是在制品 如果发送更多字节,您不太可能只获得 8 个字节。 我的 char 数组填充在 recvfrom 之后的前 8 个元素中。收到的回复应该是消息+一个8字节长8字节,我的服务器也是打印出来的,根据传入的数据,长度一般是40+字节。 UDP 知道您发送了多少,并将其作为数据报发送,并作为数据报接收。您发送和接收的内容是 1::1,除非接收缓冲区太小,当然也禁止数据报丢失、重复和序列错误。这里没有任何相反的证据。 【参考方案1】:

根据MSDN:

recvfrom 函数接收数据报并存储源地址。

对于面向消息的套接字,数据从第一个排队的消息中提取,直到指定的缓冲区大小。如果数据报或消息大于指定的缓冲区,则缓冲区被数据报的第一部分填充,并且 recvfrom 生成错误 WSAEMSGSIZE。对于不可靠的协议(例如,UDP),多余的数据会丢失。对于UDP,如果接收到的数据包不包含数据(空),recvfrom函数的返回值为零。

因此,您无法接收传入消息的一部分,只有当操作系统可以处理并返回排队的数据报时,接收才会返回。

【讨论】:

完全没有必要。 UDP 保留消息边界。 @EJP,我误读了 OP 的问题,虽然他想要多个消息缓冲。我更新了答案。 感谢@DanielTrugman。似乎我不记得 UDP 数据包是作为整体发送的,并且没有考虑我的服务器根本没有发送整个数据的可能性。【参考方案2】:

为了完整起见,并且遇到类似困惑的人发现这一点的可能性很小,解决方案如下:

是的,这是一个愚蠢的问题,我应该意识到 recvfrom 等待完整的数据报。问题出在我的服务器上。

这是服务器未发送完整数据的问题。我不确定确切的原因,但为了解决这个问题,我将我的回复存储到(并正确打印)char[] 转换为char[],发送时工作正常。

【讨论】:

以上是关于recvfrom:等待完整消息(可变大小消息,线程)的主要内容,如果未能解决你的问题,请参考以下文章

ThreadX内核源码分析 - 消息队列

ThreadX内核源码分析 - 消息队列

实现UDP高效接收/响应

使用单线程等待消息队列和套接字

节点大小可变的环形队列实现

UDP和套接字,recvfrom()返回-1,资源暂时不可用