asio:取消后重新启动async_read_some/async_write_some是否安全

asio: is it safe to restart a async_read_some/async_write_some after cancel

本文关键字:async some write 是否 安全 read 取消后 重新启动 asio      更新时间:2023-10-16

我很难在文档中找到确切的答案。

我想知道取消异步读写操作,然后重新启动操作是否会导致数据流损坏?

详细阅读:如果正在运行async_read_some操作:

  • 通过流描述符取消该操作
  • 等待处理程序完成并处理结果(使用operation_aborted或字节传输)

我能确定当我启动一个新的async_read_some操作时,没有数据丢失吗?也就是说,当处理程序返回operation_aborted错误时,没有读取任何数据?

async_write_some操作也是如此。当我取消操作,等待处理程序完成,处理结果(我再次知道返回不需要operation_abored),然后开始写入剩余数据时,流是否可能重复数据?即,当恢复写入时,取消是否会导致数据被双重写入?

cancel()本身不会导致流中的数据丢失或重复。只有当应用程序:时,数据丢失或重复才会发生在应用程序协议中

  • 使用相同的底层内存启动多个读取操作,这些操作在不处理已读取的数据的情况下成功
  • 使用相同的底层内存启动多个写入操作,这些操作在不更改已写入内存的内容的情况下成功

正确处理传递给完成处理程序的error_codebytes_transferred将防止这种形式的数据丢失或重复。如果bytes_transferred大于0,则数据已从套接字读取到缓冲区中,或者已从缓冲区写入到套接字中。请注意,如果某个操作已经被调用或在不久的将来排队等待调用,则该操作将不再可取消。考虑以下场景,其中socket具有可供读取的42字节:

assert(socket.available() == 42);
std::array<char, 32> buffer;
socket.async_read_some(boost::asio::buffer(buffer), ...); // op 1
socket.cancel();
socket.async_read_some(boost::asio::buffer(buffer), ...); // op 2
io_service.run();

如果op 1成功并且将32字节读取到buffer中,则10字节仍然可用于从socket读取。op 1的完成处理程序将在将来排队等待调用,error_code为成功,bytes_transferred32。此时,socket.cancel()op 1没有影响。在启动op 2时,剩余的10字节准备进入buffer,覆盖来自op 1的一些未处理的数据。op 2的完成处理程序将排队等待将来的调用,error_code为成功,bytes_transferred10


对于非合成操作,如socket.async_read_some():

  • 如果发生错误,例如取消,则error_code将不是boost::system::errc::success,而bytes_transferred将始终是0
  • 如果没有出现错误,则error_code将为boost::system::errc::successbytes_transferred将大于或等于0

StreamSocketService的async_receive()async_send()函数记录了这种行为:

如果操作成功完成,则会调用[handler]并传输字节数。否则使用0调用它。

另一方面,对于组合操作,例如boost::asio::async_read(),可以使用不成功的error_code和非零的bytes_transferred来调用处理程序。例如,如果async_read()操作被启动并设置为在完成之前读取1024字节,则它可以多次调用async_read_some()。如果接收到256个字节,然后连接关闭,则async_read()处理程序将具有非零的error_code,并且bytes_transferred将指示缓冲器的256个字节是有效的。