我正在c++
使用TCP/IP
和编写分布式系统sockets
。
对于我的每条消息,我需要接收前 5 个字节才能知道传入消息的完整长度。
最好的方法是什么?
recv()
只有 5 个字节,然后recv()
再一次。如果我选择这个,假设我会在 recv 中得到 0 或 5 个字节(也就是不写循环继续尝试)是否安全?- 利用
MSG_PEEK
recv()
一些更大的缓冲区大小,然后读取前 5 个字节并分配最终缓冲区。
我正在c++
使用TCP/IP
和编写分布式系统sockets
。
对于我的每条消息,我需要接收前 5 个字节才能知道传入消息的完整长度。
最好的方法是什么?
recv()
只有 5 个字节,然后recv()
再一次。如果我选择这个,假设我会在 recv 中得到 0 或 5 个字节(也就是不写循环继续尝试)是否安全?MSG_PEEK
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 个字节执行检查,并可能处理缓冲区的其余部分。切换到第二种状态。
第二国。
在字节到达消息末尾时接收并处理它们。
具体回答您的问题: