4

我正在c++使用TCP/IP和编写分布式系统sockets

对于我的每条消息,我需要接收前 5 个字节才能知道传入消息的完整长度。

最好的方法是什么?

  1. recv()只有 5 个字节,然后recv()再一次。如果我选择这个,假设我会在 recv 中得到 0 或 5 个字节(也就是不写循环继续尝试)是否安全?
  2. 利用MSG_PEEK
  3. recv()一些更大的缓冲区大小,然后读取前 5 个字节并分配最终缓冲区。
4

3 回答 3

4

不需要知道任何事情。TCP 是一种流协议,在任何给定时刻,您都可以获得少至一个字节或多至几兆字节的数据。使用 TCP 套接字的正确且唯一的方法是循环读取。

char buf[4096];        // or whatever

std::deque<char> data;

for (int res ; ; )
{
    res = recv(fd, buf, sizeof buf, MSG_DONTWAIT);

    if (res == -1)
    {
        if (errno == EAGAIN || errno == EWOULDBLOCK)
        {
            break;  // done reading
        }
        else
        {
            // error, break, die
        }
    }
    if (res == 0)
    {
        // socket closed, finalise, break
    }
    else
    {
        data.insert(data.end(), buf, buf + res);
    }
}

循环的唯一目的是将数据从套接字缓冲区传输到您的应用程序。然后,您的应用程序必须独立决定队列中是否有足够的数据来尝试提取某种更高级别的应用程序消息。

例如,在您的情况下,您将检查队列的大小是否至少为 5,然后检查前五个字节,然后检查队列是否包含完整的应用程序消息。如果不是,则中止,如果是,则提取整个消息并从队列的前面弹出。

于 2012-09-13T14:49:21.070 回答
1

使用具有两种状态的状态机:

第一州。

在字节到达缓冲区时接收它们。当有 5 个或更多字节时,对前 5 个字节执行检查,并可能处理缓冲区的其余部分。切换到第二种状态。

第二国。

在字节到达消息末尾时接收并处理它们。

于 2012-09-13T14:50:08.233 回答
0

具体回答您的问题:

  1. 假设你会得到 0 或 5 是不安全的。也有可能得到 1-4。循环直到你得到 5 或其他人建议的错误。
  2. 我不会打扰PEEK,大多数时候你会阻塞(假设阻塞调用)或得到5所以跳过额外的调用进入堆栈。
  3. 这也很好,但增加了复杂性却收效甚微。
于 2012-09-13T17:00:53.037 回答