繁体   English   中英

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

[英]recv the first few bytes from a socket to determine buffer size

我正在使用TCP/IPsocketsc++编写一个分布式系统。

对于我的每条消息,我需要接收前5个字节来了解传入消息的完整长度。

最好的方法是什么?

  1. recv()仅5个字节,然后再次recv() 如果选择此选项,可以安全地假设我将在recv中获得0或5个字节(也就是不编写循环来继续尝试)吗?
  2. 使用MSG_PEEK
  3. recv()较大的缓冲区大小,然后读取前5个字节,然后分配最终缓冲区。

不需要知道的任何事情。 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,然后检查前五个字节,然后检查队列是否包含完整的应用程序消息。 如果不是,则中止,如果是,则提取整个消息,如果从队列的最前面弹出则弹出。

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

第一状态。

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

第二状态。

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

具体回答您的问题:

  1. 假设您会得到0或5是不安全的。也可能会得到1-4。 循环直到得到5或其他人建议的错误。
  2. 我不会打扰PEEK,在大多数情况下,您会阻塞(假设阻塞调用)或得到5个,因此跳过多余的调用进入堆栈。
  3. 这也很好,但增加了复杂性却几乎没有收益。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM