boost :: asio :: buffer:获取缓冲区大小并防止缓冲区溢出?

pan*_*ami 8 c++ buffer-overflow boost-asio

我有以下两个用于发送和接收数据包的功能.

void send(std::string protocol)
{
    char *request=new char[protocol.size()+1];
    request[protocol.size()] = 0;
    memcpy(request,protocol.c_str(),protocol.size());

    request_length = std::strlen(request);
    boost::asio::write(s, boost::asio::buffer(request, request_length));
}
void receive()
{
    char reply[max_length];
    size_t reply_length = boost::asio::read(s, boost::asio::buffer(reply, request_length));
    std::cout << "Reply is: ";
    std::cout.write(reply, reply_length);
    std::cout << "\n";
}
Run Code Online (Sandbox Code Playgroud)

问题与此部分有关,boost::asio::buffer(reply, request_length)其中请求长度是在发送数据包时最初设置的字符串的长度.如何在不知情的情况下检查缓冲区的大小request_length?另一个问题是如何防止缓冲区溢出?

Tan*_*ury 15

要获得缓冲区的大小,boost::asio::buffer_size()可以使用该函数.但是,在您的示例中,这很可能对您没用.

如缓冲区概述中所述,Boost.Asio使用缓冲区类来表示缓冲区.这些类提供抽象并保护Boost.Asio操作免受缓冲区溢出的影响.虽然结果boost::asio::buffer()传递给操作,但不传输元数据,例如缓冲区的大小或其基础类型.此外,这些缓冲区不拥有内存,因此应用程序有责任确保底层内存在缓冲区抽象的生命周期内保持有效.

boost::asio::buffer()函数提供了一种创建缓冲区类的便捷方法,其中缓冲区的大小是从可能的类型推导出来的.当Boost.Asio能够推断出缓冲区长度时,Boost.Asio操作在使用生成的缓冲区类型时不会调用缓冲区溢出.但是,如果应用程序代码指定缓冲区的大小boost::asio::buffer(),则应用程序有责任确保大小不大于底层内存.

读取数据时,需要缓冲区.如果Boost.Asio不传输大小,那么基本问题就是如何知道要分配多少内存.这个问题有几个解决方案:

  • 查询套接字是否有可用的数据socket::available(),然后相应地分配缓冲区.

    std::vector<char> data(socket_.available());
    boost::asio::read(socket_, boost::asio::buffer(data));
    
    Run Code Online (Sandbox Code Playgroud)
  • 使用Boost.Asio可以在内存中增长的类,例如boost::asio::streambuf.某些操作,例如boost::asio::read()接受streambuf对象作为其缓冲区,并将按操作所需的内容分配内存.但是,应提供完成条件; 否则,操作将继续,直到缓冲区已满.

    boost::asio::streambuf data;
    boost::asio::read(socket_, data,
                      boost::asio::transfer_at_least(socket_.available()));
    
    Run Code Online (Sandbox Code Playgroud)
  • 正如ÖöTiib建议的那样,将长度作为通信协议的一部分.检查Boost.Asio 示例以获取通信协议的示例.专注于协议,不一定在Boost.Asio API上.

    • 在固定大小的协议中,数据生产者和消费者都使用相同大小的消息.当读者知道消息的大小时,读者可以提前分配缓冲区.
    • 在可变长度协议中,消息通常分为两部分:标题和正文.标题通常是固定大小,并且可以包含各种元信息,例如正文的长度.这允许读者将标题读入固定大小的缓冲区,提取体长,为身体分配缓冲区,然后读取体.

      // Read fixed header.
      std::vector<char> data(fixed_header_size);
      boost::asio::read(socket_, boost::asio::buffer(data));
      
      protocol::header header(data);
      network_to_local(header); // Handle endianess.
      
      // Read body.
      data.resize(header.body_length());
      boost::asio::read(socket_, boost::asio::buffer(data));  
      
      protocol::body body(data);
      network_to_local(body); // Handle endianess.    
      
      Run Code Online (Sandbox Code Playgroud)


Öö *_*iib 5

通常,通信协议使用固定长度的消息或包含告知消息长度的标头的消息.

Boost.Asio在线文档包含大量示例和教程,因此您应该从那里开始.维基百科是解释数据传输术语的良好来源,提升asio文档并没有这样做.

  • 我已经浏览过 boost asio 教程,但那些只是掩盖了示例,并没有详细解释函数调用的作用、返回的内容等。我知道我也可以查看 hpp 文件,但那就是这是大海捞针,甚至比例子本身更无用。另外,我确信有很多东西在 boost 示例/教程中没有提到,但只能在 hpp 文件中找到,这可能需要多年的练习才能使用。 (2认同)