我很难在文档中找到明确的答案。
我想知道取消异步读取或写入操作然后稍后重新启动操作是否会导致数据流损坏?
详细阅读:如果 async_read_some 操作正在运行:
- 通过流描述符取消该操作
- 等待处理程序完成并处理结果(使用操作中止或传输字节)。
我能否确定当我开始新的 async_read_some 操作时不会丢失任何数据? IE。当处理程序返回 operation_aborted 错误时,没有读取任何数据?
对于 async_write_some 操作也是如此。当我取消操作时,等待处理程序完成,处理结果(再次我知道返回不需要操作_中止),然后开始写入剩余数据,流是否有可能重复数据? IE。取消会导致恢复写入时数据被重复写入吗?
最佳答案
就其本身而言,cancel()
不会导致流中的数据丢失或重复。仅当应用程序满足以下条件时,才会在应用程序协议(protocol)中发生数据丢失或重复:
- 使用相同的底层内存启动多个读取操作,这些操作在不处理已读取的数据的情况下成功
- 使用相同的底层内存发起多个成功的写入操作,但不会更改已写入的内存内容
正确处理传递给完成处理程序的error_code
和bytes_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_transferred
为 32
。此时,socket.cancel()
对 op 1
没有任何影响。启动op 2
后,10
剩余字节已准备好进入缓冲区
,覆盖op 1中的一些未处理的数据
。 op 2
的完成处理程序将排队等待将来调用,error_code
为成功,bytes_transferred
为 10
.
对于非组合操作,例如 socket.async_read_some()
:
- 如果发生错误,例如取消,则
error_code
将不会是boost::system::errc::success
和bytes_transferred
永远是0
- 如果没有发生错误,则
error_code
将是boost::system::errc::success
并且bytes_transferred
将更大大于或等于0
此行为已记录在 StreamSocketService 中的 async_receive()
和 async_send()
函数:
If the operation completes successfully, the [handler] is invoked with the number of bytes transferred. Otherwise it is invoked with
0
.
另一方面,使用组合操作,例如 boost::asio::async_read()
,可以使用非成功的 error_code
和非零的 bytes_transferred
来调用处理程序。例如,如果启动 async_read()
操作并设置为在完成之前读取 1024 字节,则它可能会多次调用 async_read_some()
。如果收到 256 个字节,然后关闭连接,async_read()
处理程序将有一个非零 error_code
并且 bytes_transferred
将指示:缓冲区的 256 字节有效。
关于c++ - 亚洲 : is it safe to restart a async_read_some/async_write_some after cancel,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36334161/