【问题标题】:boost::asio::buffer: Getting the buffer size and preventing buffer overflow?boost::asio::buffer:获取缓冲区大小并防止缓冲区溢出?
【发布时间】:2013-02-10 05:23:50
【问题描述】:

我有以下两个发送和接收数据包的函数。

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

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

【问题讨论】:

    标签: c++ boost-asio buffer-overflow


    【解决方案1】:

    通常,通信协议要么使用固定长度的消息,要么使用包含标明消息长度的标头的消息。

    Boost.Asio online documentation 包含大量示例和教程,因此您或许应该从那里开始。维基百科是解释data transmission 术语的好来源,boost asio 文档没有这样做。

    【讨论】:

    • 我已经浏览了 boost asio 教程,但那些只是掩盖了示例,并没有详细解释函数调用的作用、它们返回的内容等。我知道我可以看看也进入 hpp 文件,但这就像大海捞针,甚至比示例本身更无用。另外,我确信在 boost 示例/教程中没有说很多东西,但只能在 hpp 文件中找到,这可能需要多年的练习才能使用。
    • @lost_with_coding 也许 boost asio 示例希望人们熟悉数字通信的概念以及示例中使用的协议、客户端、服务器、请求等相关术语的含义。我建议不要从代码中对此类知识进行逆向工程,因为有更容易的资源来学习所有这些知识。
    • @lost_with_coding:examples 没有解释 API 的作用,因为它记录在 reference 部分中。 Boost.Asio 库很复杂,并不复杂。文档中有大量信息,可能值得花时间熟悉文档的各个部分。
    • @twsansbury 感谢参考链接很有用。从来不知道它的存在。
    【解决方案2】:

    要获取缓冲区的大小,可以使用boost::asio::buffer_size() 函数。但是,在您的示例中,这很可能对您没有什么用处。

    正如缓冲区overview 中所解释的,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));
      
    • 使用 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()));
      
    • 正如Öö Tiib 建议的那样,将长度作为通信协议的一部分。检查 Boost.Asio examples 以获取通信协议的示例。专注于协议,不一定是 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.    
        

    【讨论】:

    • 好东西。在消息以分隔符结尾的情况下,boost::asio::streambuffboost::asio::read_until() 对我来说效果很好。
    【解决方案3】:

    我认为您的问题令人困惑,但这可能会有所帮助:

    void receive() {
      enum { max_length = 1024 };
      char reply[max_length];
      size_t reply_length;
      std::cout << "Reply is: ";
      while ( (reply_length = ba::read(s, basio::buffer(reply, max_length))) > 0) {
        std::cout.write(reply, reply_length);
      }
      std::cout << "\n";
    }
    

    【讨论】:

    • boost::asio::buffer(,) 究竟返回了什么。我看到它在ba::read(s,buffer(,)) 中返回了一些东西,但它是什么?
    • @lost_with_coding:表示内存但不拥有内存的类型。 function 有助于调整常用类型,使其满足许多 Boost.Asio 操作的类型要求。这个overview 提供了一些信息。
    • 在此示例中,您不必将 max_length 传递给 asio::buffer()。 (因为 asio 可以使用 sizeof 获取它。)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-12-24
    • 2018-07-26
    • 2013-05-27
    • 1970-01-01
    相关资源
    最近更新 更多