我有一个非常简单的方法,目的是响应传入的消息,然后关闭连接:
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/