You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Boost::Asio读取缓冲区时出现乱码的原因及解决方法

问题:Boost.Asio async_read_until读取数据出现乱码

我有一个客户端程序负责读取文件并逐行将ASCII编码的数据发送至服务器,服务器需要统计发送的行数。使用boost::asio::async_read_until实现时,从缓冲区读取数据出现乱码(例如:Line: �68�)。

客户端代码片段

std::ifstream infile(argv[1]);
std::string line;

while (std::getline(infile, line)) {
  boost::asio::write(s, boost::asio::buffer(line + '\n'));
  std::cout << line << std::endl;

服务器读取函数代码片段

void handle_read(const boost::system::error_code& error, size_t bytes_trasferred, boost::asio::streambuf& buf)
{
  if (!error)
  {
      if (!bytes_trasferred)
      {
          std::cout << "0 bytes trasferred\n";
          return;
      }

      std::string data = boost::asio::buffer_cast<const char*>(buf.data());
      std::istringstream is(data);
      std::string line;
      std::getline(is, line);
      std::cout << "Line: " << line << std::endl;    
  }
  else
    std::cerr << "Error: " << error.message() << std::endl;
}

void do_read()
{
    std::cout << "do_read\n";
    auto self(shared_from_this());
    boost::asio::streambuf buf;
    buf.prepare(1048576);
    std::cout << "ASYNC\n";
    boost::asio::async_read_until(socket_, buf, "\n",
        boost::bind(&TcpConnection::handle_read, this, boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred, boost::ref(buf)));
}

已尝试的方案:

  • 使用self和this替代绑定对象,导致内存泄漏
  • 在处理函数中获取数据后添加空终止符,问题仍未解决

解决方案

问题根源

  1. 局部缓冲区生命周期错误:do_read中声明的局部boost::asio::streambuf buf,在异步操作发起后函数返回,缓冲区会被销毁,但回调handle_read仍会引用该已释放的内存,导致非法访问出现乱码。
  2. 缓冲区数据处理错误:直接通过buffer_cast获取整个streambuf的数据,未考虑async_read_until返回的bytes_transferred是匹配分隔符的有效字节数,且streambuf数据并非空字符结尾,直接赋值给std::string会读取到缓冲区中未初始化的垃圾数据。

修复步骤

1. 修正缓冲区生命周期

将streambuf改为TcpConnection类的成员变量,确保异步操作完成前缓冲区不会被销毁:

class TcpConnection : public std::enable_shared_from_this<TcpConnection>
{
private:
    boost::asio::streambuf buf_; // 类成员缓冲区
    // ... 其他成员变量
};

修改do_read函数,使用类成员缓冲区:

void do_read()
{
    std::cout << "do_read\n";
    auto self(shared_from_this());
    buf_.prepare(1048576);
    std::cout << "ASYNC\n";
    boost::asio::async_read_until(socket_, buf_, "\n",
        boost::bind(&TcpConnection::handle_read, shared_from_this(), 
            boost::asio::placeholders::error, 
            boost::asio::placeholders::bytes_transferred, 
            boost::ref(buf_)));
}

2. 正确读取有效数据并清理缓冲区

在handle_read中,直接通过std::istream读取streambuf,并提交已消费的数据避免重复读取:

void handle_read(const boost::system::error_code& error, size_t bytes_transferred, boost::asio::streambuf& buf)
{
    if (!error)
    {
        if (!bytes_transferred)
        {
            std::cout << "0 bytes transferred\n";
            do_read();
            return;
        }

        std::istream is(&buf);
        std::string line;
        std::getline(is, line);
        std::cout << "Line: " << line << std::endl;    

        // 提交已读取的数据,清理缓冲区中已消费的部分
        buf.consume(bytes_transferred);

        do_read(); // 继续监听下一行数据
    }
    else
    {
        std::cerr << "Error: " << error.message() << std::endl;
    }
}

3. 确保连接对象生命周期

使用shared_from_this()绑定回调,保证TcpConnection对象在异步操作完成前不会被销毁,避免内存泄漏或悬空引用。


内容的提问来源于stack exchange,提问作者CupaState

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.01 09:05:38