我目前正在使用Boost Asio实现一个网络协议。域类已经存在,并且我能够连续两次调用boost :: asio :: read检索正确的数据
- 写入数据包发送到
std::istream
- 和读取从
std::ostream
包。
甲网络分组包含网络分组报头。头部以数据包长度字段开头,其字段大小为两个字节(std::uint16_t
)。
我使用TCP/IPv4的作为传输层,因此我尝试执行以下操作:
- 读取数据包的长度,以了解它的总长度。这意味着只需从套接字读取两个字节。
- 阅读数据包的其余部分。这意味着从套接字准确读取
kActualPacketLength - sizeof(PacketLengthFieldType)
个字节。 - Concat都读取二进制数据。
因此,我需要至少两个电话boost::asio::read
(我开始同步!)。
我能有一个调用来读取数据包到boost::asio::read
如果我硬编码期望的长度:
Packet const ReadPacketFromSocket() {
boost::asio::streambuf stream_buffer;
boost::asio::streambuf::mutable_buffers_type buffer{
stream_buffer.prepare(Packet::KRecommendedMaximumSize)};
std::size_t const kBytesTransferred{boost::asio::read(
this->socket_,
buffer,
// TODO: Remove hard-coded value.
boost::asio::transfer_exactly(21))};
stream_buffer.commit(kBytesTransferred);
std::istream input_stream(&stream_buffer);
PacketReader const kPacketReader{MessageReader::GetInstance()};
return kPacketReader.Read(input_stream);
}
这读取一次完整的分组数据并返回Packet
实例。这是有效的,所以这个概念正在起作用。
到目前为止这么好。现在我的问题:
如果我连续拨打boost::asio::read
与boost::asio::streambuf
我不能得到它的工作。
下面是代码:
Packet const ReadPacketFromSocket() {
std::uint16_t constexpr kPacketLengthFieldSize{2};
boost::asio::streambuf stream_buffer;
boost::asio::streambuf::mutable_buffers_type buffer{
stream_buffer.prepare(Packet::KRecommendedMaximumSize)};
std::size_t const kBytesTransferred{boost::asio::read(
// The stream from which the data is to be read.
this->socket_,
// One or more buffers into which the data will be read.
buffer,
// The function object to be called to determine whether the read
// operation is complete.
boost::asio::transfer_exactly(kPacketLengthFieldSize))};
// The received data is "committed" (moved) from the output sequence to the
// input sequence.
stream_buffer.commit(kBytesTransferred);
BOOST_LOG_TRIVIAL(debug) << "bytes transferred: " << kBytesTransferred;
BOOST_LOG_TRIVIAL(debug) << "size of stream_buffer: " << stream_buffer.size();
std::uint16_t packet_size;
// This does seem to modify the streambuf!
std::istream istream(&stream_buffer);
istream.read(reinterpret_cast<char *>(&packet_size), sizeof(packet_size));
BOOST_LOG_TRIVIAL(debug) << "size of stream_buffer: " << stream_buffer.size();
BOOST_LOG_TRIVIAL(debug) << "data of stream_buffer: " << std::to_string(packet_size);
std::size_t const kBytesTransferred2{
boost::asio::read(
this->socket_,
buffer,
boost::asio::transfer_exactly(packet_size - kPacketLengthFieldSize))};
stream_buffer.commit(kBytesTransferred2);
BOOST_LOG_TRIVIAL(debug) << "bytes transferred: " << kBytesTransferred2;
BOOST_LOG_TRIVIAL(debug) << "size of stream_buffer: " << stream_buffer.size();
// Create an input stream with the data from the stream buffer.
std::istream input_stream(&stream_buffer);
PacketReader const kPacketReader{MessageReader::GetInstance()};
return kPacketReader.Read(input_stream);
}
我有以下问题:
- 读取来自
boost::asio::streambuf
数据包长度的第一插槽读取似乎从boost::asio::streambuf
删除数据之后。 - 如果我使用两个截然不同的
boost::asio::streambuf
实例,我不知道如何“连接”/“追加”它们。
在一天结束时,我需要一个std::istream
与从套接字获得正确的数据。
有人可以引导我进入正确的方向吗?我试图让这项工作现在几个小时...
也许这种方法不是最好的,所以我愿意提出改进我的设计的建议。
谢谢!
你确定你的代码编译?我无法让它与GCC 4.7.1和Boost 1.55.0一起工作。我还喜欢使用一个'streambuf'作为我的例子。 –
我打错了'ostream' :)当然你可以有一个r/w流(记得在适当的时候寻找原点) – sehe
你能详细说明吗?我确实需要一个'std :: istream'对象将它传递给我的PacketReader。另一个问题是,如果我从中读取数据包的长度,第一个'streambuf'就会被修改。是不是可以使用** 1 **'streambuf'来读取两个套接字(并从中读取'streambuf'),以便通过第二次读取附加'streambuf'? –