Boost::Asio::Read 没有填充缓冲区

Posted

技术标签:

【中文标题】Boost::Asio::Read 没有填充缓冲区【英文标题】:Boost::Asio::Read is not populating buffer 【发布时间】:2021-06-21 19:29:18 【问题描述】:

这是我的服务器类,它在连接时呈现异步事件以向我的客户端发送字符串。

消息肯定会发送到客户端,因为 writehandler 被成功调用而没有任何错误:

class Server 
private:

    void writeHandler(ServerConnection connection, const boost::system::error_code &error_code,
                      std::size_t bytes_transferred) 

        if (!(error_code)) 
            std::cout << "SENT "<<bytes_transferred <<" BYTES"<< std::endl;
        
    

    void renderWriteEvent(ServerConnection connection, const std::string& str) 
        std::cout << "RENDERING WRITE EVENT" << std::endl;
        connection->write = str;
        boost::asio::async_write(connection->socket, boost::asio::buffer(connection->write),
                                 boost::bind(&Server::writeHandler, this, connection,
                                             boost::asio::placeholders::error,
                                             boost::asio::placeholders::bytes_transferred));
    
    

;

现在在客户端,成功连接到服务器后,我调用

        void renderRead()
        std::cout<<"Available Bytes: "<<socket.available()<<std::endl;
        std::string foo;


        boost::system::error_code error_code;
        std::size_t x = socket.read_some(boost::asio::buffer(foo), error_code);
        std::cout<<error_code.message()<<std::endl;

        std::cout<<"Bytes read: "<<x<<std::endl;
        std::cout<<"Available Bytes: "<<socket.available()<<std::endl;
        std::cout<<foo<<std::endl;
        //boost::asio::async_read(socket, boost::asio::buffer(read_string), boost::bind(&Client::readHandler, this, boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred));
    

输出“可用字节数:12”

然后,在调用 boost::asio::read 时,我读取了 0 个字节,并且没有错误。我不明白出了什么问题。读取后,socket流中可供读取的字节数仍然打印为12

【问题讨论】:

@Frank 我怎样才能动态调整字符串的大小以适应所有消息? 你必须在循环中调用read_some(),在每次调用时传递一个固定大小的缓冲区,直到接收到所有数据。 【参考方案1】:

这里的一个关键点是read_some() 不分配任何内存,它会填充提供给它的内存。对于您的代码,这意味着 ASIO 只会替换 foo 中已经存在的数据,并且永远不会超出这些界限。

但是你有std::string foo;,这是一个默认构造的字符串,也就是一个字符串。

所以 ASIO 可以很好地填充您传递的缓冲区。但是,您传递给它的是一个没有空间的缓冲区。 ASIO 尽可能地填充它:0 字节。

您可以通过将以下代码添加到您的代码中来自行测试:

std::string foo;
std::cout << "Available room in buffer: "<< foo.size() << std::endl;

解决方法是传递一个已分配内存的缓冲区。您可以使用长度初始化字符串,但使用稍后解释为string_view 的原始字节块更明确。

constexpr std::size_t buffer_size = 32;

std::array<char, buffer_size> foo;
std::size_t x = socket.read_some(boost::asio::buffer(foo), error_code);

//...

std::string_view message(foo.data(), x);
std::cout << message << std::endl;


【讨论】:

以上是关于Boost::Asio::Read 没有填充缓冲区的主要内容,如果未能解决你的问题,请参考以下文章

boost::asio::read 函数挂起

为啥 boost::asio::read 缓冲区数据大小小于读取大小?

Boost::asio async_read 简单文件上传

实现真正 boost::asio::async_read_until 的最简单方法

boost asio async_read中的随机EOF

传递给 boost::asio::async_read_some 的回调从未在 boost::asio::read_some 返回数据的使用中调用