提升 ASIO 在基于 TCP 的协议中查找消息的开头
boost asio find beginning of message in tcp based protocol
我想为通过 tcp 发送数据并使用以下协议的传感器实现一个客户端:
- 消息头以类型
uint32
的字节序列0xAFFEC0CC2
开头 - 标头总共为 24 字节长(包括开始序列(,并包含消息正文的大小(以字节为单位(作为
uint32
- 消息正文直接在标头之后发送,而不是由半音终止
目前,我得到了以下代码(假设存在连接的套接字(
typedef unsigned char byte;
boost::system::error_code error;
boost::asio::streambuf buf;
std::string magic_word_s = {static_cast<char>(0xAF), static_cast<char>(0xFE),
static_cast<char>(0xC0), static_cast<char>(0xC2)};
ssize_t n = boost::asio::read_until(socket_, buf, magic_word_s, error);
if(error)
std::cerr << boost::system::system_error(error).what() << std::endl;
buf.consume(n);
n = boost::asio::read(socket_, buf, boost::asio::transfer_exactly(20);
const byte * p = boost::asio::buffer_cast<const byte>(buf.data());
uint32_t size_of_body = *((byte*)p);
不幸的是,read_until文档备注:
成功执行read_until操作后,streambuf 可能包含分隔符以外的其他数据。应用程序通常会将该数据保留在 streambuf 中,以供后续read_until操作进行检查。
这意味着我失去了与所描述协议的同步。 有没有一种优雅的方法可以解决这个问题?
嗯...正如它所说...您只需将其"保留"在对象中,或将其临时存储在另一个对象中,并在完成时处理整个消息(下面称为"数据包"(。
在我的一个项目中,我也有类似的方法。我将解释一下我是如何做到的,这应该可以让您大致了解如何正确处理数据包。
在我的读取处理程序(回调(中,我一直在检查数据包是否完整。元数据信息(您的标头(临时存储在与远程合作伙伴关联的地图中(map<RemoteAddress,InfoStructure>(。
例如,它可能看起来像这样:
4 byte identifier
4 byte message-length
n byte message
处理传入数据,检查标识符+消息长度是否已经接收,继续检查消息数据是否用接收到的数据完成。
将数据包的其余部分留在临时缓冲区中,擦除旧数据。
当下一个数据包到达时继续处理,或检查接收的数据是否已经完成下一个数据包...
这种方法可能听起来有点慢,但我甚至可以在慢速机器上使用 SSL 10MB/s+。
如果没有SSL,更高的传输速率是可能的。
使用此方法,您还可以查看read_some或其异步版本。
相关文章:
- 协议缓冲区ParseFromString不检查消息结尾
- 提升 ASIO 在基于 TCP 的协议中查找消息的开头
- 协议缓冲区#3将消息从c ++发送到c#
- Steam协议C 解压缩多消息
- Tcp 协议前缀消息的长度
- 将二进制数据缓冲区存储在协议缓冲区消息中
- 如何将多个协议缓冲区的消息写入可附加的压缩文件中?
- C++中的Google协议缓冲区:从现有结构中创建消息
- 协议缓冲区-读取所有消息中通用的标头(嵌套消息)
- Arduino不支持使用websocket协议发送超过65535个字符的消息
- 用于使用 istream/ostream 传输消息的类似网络协议
- 在调试模式下销毁协议缓冲区消息几乎比在发布模式下慢 500 倍
- 如何在mavlink协议中添加新消息
- 协议缓冲cpp嵌入的消息
- 如何将 boost::asio 用于没有标头告诉我消息大小的 TCP 协议?
- 在外部消息中包括预编码的协议缓冲区消息
- 如何在协议缓冲区中设置嵌套消息的字段
- 是否可以使用 Varint32 大小前缀的协议缓冲区消息实现类似"FileInputStream::BackUp()"的功能?
- 协议和非阻塞消息发送/接收
- 如何在协议缓冲区c++教程中编写消息