gpt4 book ai didi

c++ - 通过连续两次调用 boost::asio::read 检索正确的数据

转载 作者:可可西里 更新时间:2023-11-01 02:46:47 25 4
gpt4 key购买 nike

我目前正在使用 Boost Asio 实现网络协议(protocol).域类已经存在,我能够

  • 将数据包写入std::istream
  • 并从 std::ostream 中读取数据包。

一个网络包包含一个网络包头。 header 以 Packet Length 字段开始,其大小为两个字节 (std::uint16_t)。

我使用 TCP/IPv4 作为传输层,因此我尝试实现以下内容:

  1. 读取数据包的长度以了解其总长度。这意味着从套接字中读取两个字节。
  2. 阅读数据包的其余部分。这意味着从套接字中准确读取 kActualPacketLength - sizeof(PacketLengthFieldType) 个字节。
  3. 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::streambuf 连续两次调用 boost::asio::read,我将无法正常工作。

代码如下:

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);
}

我有以下问题:

  1. 在第一次套接字读取后从 boost::asio::streambuf 读取数据包长度似乎从 boost::asio::streambuf 中删除了数据。
  2. 如果我使用两个不同的 boost::asio::streambuf 实例,我不知道如何“连接”/“追加”它们。

归根结底,我需要一个包含从套接字获取的正确数据的 std::istream

有人可以指导我正确的方向吗?我已经尝试让这项工作几个小时了......

也许这种方法不是最好的,所以我愿意接受改进我的设计的建议。

谢谢!

最佳答案

  1. 我相信这种行为是设计使然的。

  2. 要连接缓冲区,您可以使用 BUfferSequences(使用 make_buffers)并使用缓冲区迭代器,或者您可以将第二个流式传输到第一个:

    boost::asio::streambuf a, b;
    std::ostream as(&a);

    as << &b;

    现在您可以丢弃 b,因为它的未决数据已附加到 a

查看 Live on Coliru

关于c++ - 通过连续两次调用 boost::asio::read 检索正确的数据,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24695395/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com