c++ - boost::asio::async_write 和缓冲区超过 65536 字节

标签 c++ boost boost-asio

我有一个非常简单的方法,目的是响应传入的消息,然后关闭连接:

void respond ( const std::string message )
{ 
  std::string str = "<?xml version=\"1.0\"?>";

  Controller & controller = Controller::Singleton(); 
  if ( auto m = handleNewMessage( _message ) )
  {
    auto reply = controller.FIFO( m );
    str.append( reply );
  }
  else
    str.append ( "<Error/>" );

  std::size_t bytes = str.size() * sizeof( std::string::value_type );
  std::cout << "Reply bytesize " << bytes << std::endl;

  boost::asio::async_write(
            socket_,
            boost::asio::buffer( str ),
            boost::bind(
                    &TCPConnection::handle_write,
                    shared_from_this(),
                    boost::asio::placeholders::error,
                    boost::asio::placeholders::bytes_transferred
                  ));
}


void handle_write ( const boost::system::error_code & error, size_t bytes_transferred )
{
  if ( error )
  {
    std::cerr << "handle_write Error: " << error.message() << std::endl;
    std::cerr << "handle_write Bytes sent: " << bytes_transferred << std::endl;
  }
  else
  {
      std::cerr << "handle_write Bytes sent: " << bytes_transferred << std::endl;
      socket_.close();
  }
}

我知道问题是boost::asio::async_write没有完成写操作,因为上面操作的输出是:

Reply bytesize: 354275
handle_write Bytes sent: 65536

暗示最大缓冲区大小(65536)不足以写入数据?

四处搜索 Stack Overflow ,我发现我的问题是方法创建的缓冲区:

boost::asio::buffer( str )

在操作有机会完成发送所有数据之前超出范围。

似乎我不能使用 boost::asio::mutable_buffer,只能使用 boost::asio::streambuf

此外,更重要的是,第二个错误提示实际的 boost::asio::async_write 被传递给 boost::asio::const_buffer 或 boost::asio::mutable_buffer:

/usr/include/boost/asio/detail/consuming_buffers.hpp:164:5: error: no type named ‘const_iterator’ in ‘class boost::asio::mutable_buffer’
     const_iterator;
     ^
/usr/include/boost/asio/detail/consuming_buffers.hpp:261:36: error: no type named ‘const_iterator’ in ‘class boost::asio::mutable_buffer’
   typename Buffers::const_iterator begin_remainder_;

所以我只有一个选择:使用 boost::asio::streambuf

我试过使用:

  boost::asio::streambuf _out_buffer;

作为类成员,然后让方法响应:

  std::ostream os( &_out_buffer );
  os << str;

  boost::asio::async_write(
            socket_,
            _out_buffer,
            boost::asio::transfer_exactly( bytes ),
            boost::bind(
                    &TCPConnection::handle_write,
                    shared_from_this(),
                    boost::asio::placeholders::error,
                    boost::asio::placeholders::bytes_transferred
                  ));

然而,虽然我没有收到任何错误,但并没有发送全部数据! 所以,我猜,不是整个字符串都写入了 streambuf?

或者,我很想知道使用 boost::asio::async_write 写入大于 65536 字节的数据的最优雅方式是什么!

最佳答案

Alex,你对asio异步操作的理解有误。您的问题全都与缓冲区和套接字的生命周期有关。 在整个传输时间内缓冲区必须处于事件状态并且套接字打开(从 asio::async_write 调用到 handle_write 回调将由 Asio io_service 调度程序调用。 为了更好地理解它是如何工作的,考虑一下每次你做一些 boost::asio::async_{operation}您正在将指向数据的指针和指向回调函数的指针发布到作业队列。何时执行您的工作由 Asio 决定(但当然它会尝试尽可能快地完成 =))。当整个(可能很大的)I/O 操作完成时,Asio 会使用指定的回调通知您。然后可以自由释放资源。

因此,为了让您的代码正常工作,您必须确保 std::string str仍然存在并且_socket直到 handle_write 才关闭打回来。您可以替换分配的堆栈 std::string str由聚合类中的某个成员变量变量 _socket .并移动 socket_.close();来自 respond 的行功能handle_write .

希望,我帮助了你。

附言当你做 boost::asio::buffer( str ),您不复制字符串的内容,而只是在字符串数据之上创建薄的 wpapper。

关于c++ - boost::asio::async_write 和缓冲区超过 65536 字节,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21120361/

相关文章:

c++ - boost 变换迭代器和 c++11 lambda

c++ - 从 std::function 创建一个 boost::python::object

c++ - 在 boost::asio 程序中刷新缓冲区

c++ - Boost::Asio - async_accept 处理程序中的 async_wait 使应用程序崩溃

C++ 构造函数采用大小为 1 的 std::initializer_list

c++ - 将 CMake 与同一语言的多个编译器一起使用

c++ - m.find(...) == m.end() - 使用的是 iterator 或 const_iterator

c++ - 为什么我要在 C++ 中实现我自己的双向链表?

c++ - async_connect 在 boost::asio 中阻塞 io_service::run_one()

c++ - 从语义 Action 更新综合属性值