boost::asio::async_write和超过65536字节的缓冲区
boost::asio::async_write and buffers over 65536 bytes
我有一个非常简单的方法,目的是响应传入消息,然后关闭连接:
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:
此外,更重要的是,第二个错误抱怨实际的boost::asio::async_write被传递了boost:
/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_;
所以我只有一个选择:使用增强::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::async_write
调用到handle_write
回调由Asioio_service
调度器调用)。为了更好地理解它是如何工作的,请考虑每次执行boost::asio::async_{operation}
时,都会将指向操作数据的指针和指向回调函数的指针发布到作业队列。何时执行你的工作是阿西奥的决定(但它当然会尽可能快地完成)。当整个(可能很大的)I/O操作完成时,Asio会使用指定的回调通知您。然后你可以自由地释放资源。
因此,要使代码正常工作,必须确保std::string str
仍然存在,并且_socket
在handle_write
回调之前不会关闭。您可以用协定_socket
的类中的某个成员变量替换堆栈分配的std::string str
变量。并将socket_.close();
行从respond
函数移动到handle_write
。
希望,我帮了你。
附言:当您执行boost::asio::buffer( str ),
时,您不复制字符串的内容,而只是在字符串的数据之上创建一个精简的wpapper。
代码:
_out_buffer( static_cast<void*>( &str.front() ), bytes );
仅在初始化_out_buffer
时有效,即在类的构造函数体开始之前。
这个代码相当于
_out_buffer.operator()( static_cast<void*>(&str.front()), bytes )
当然,类mutable_buffer
中没有这样的运算符,而这正是编译器所抱怨的。
我认为最简单的事情(但不是最好的)是将该行更改为:
_out_buffer = boost::asio::mutable_buffer(
static_cast<void*>( &str.front() ),
bytes
);
- 从不同线程使用int64的不同字节安全吗
- 将Integer转换为4字节的unsined字符矢量(按大端字节顺序)
- 在UNIX系统中使用DIR查找文件的字节大小
- 如何使用Crypto++并为RSA返回可打印的字节/字符数组
- std::当在256字节边界上写入整数时,流的奇怪行为
- 当比特(而不是字节)的顺序至关重要时的持久性
- 从文件中读取多个字节,并将它们存储在C++中进行比较
- 如何在文件中查找字节序列
- luaL_dofile在已知良好的字节码上失败,可以使用未编译的版本
- 字节到位运算符重载C++
- 在java中读取c++字节的位字段
- 使用 std::vector::reverse_iterator 将 int 序列化为字节向量?
- 字节真的是最小可寻址单元吗
- struct.error:解压缩 C++ 结构时,解包需要 288 字节的缓冲区
- 读取文件中所有可能的十六进制 16 字节序列并打印每个序列
- 如何使用 OpenCV 解码在两个 UWP 应用之间发送的图像字节?
- 如何将字节数组元素替换为修改的十六进制 ASCII 符号?
- 如何在65536字节上编码二进制数据到C 上的WebSocket帧
- boost::asio::async_write和超过65536字节的缓冲区
- Boost::asio读取大于65536字节的文件失败.处理步骤