从套接字中恢复前几个字节以确定缓冲区大小

时间:2012-09-13 14:35:27

标签: c++ sockets network-programming

我正在使用c++TCP/IPsockets编写分布式系统。

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

最好的方法是什么?

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

3 个答案:

答案 0 :(得分: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,然后检查前五个字节,然后检查队列是否包含完整的应用程序消息。如果不是,则中止,如果是,则提取整个消息,如果从队列前面关闭则弹出。

答案 1 :(得分:1)

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

第一州。

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

第二州。

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

答案 2 :(得分:0)

具体回答你的问题:

  1. 假设你得到0或5是不安全的。也可以得到1-4。循环,直到你得到5或其他人建议的错误。
  2. 我不会打扰PEEK,大部分时间你会阻止(假设阻塞调用)或者获得5,所以跳过额外的调用进入堆栈。
  3. 这也很好但增加了复杂性,但收益微薄。