boost::asio::async_write_some - 顺序函数调用

boost::asio::async_write_some - sequential function call

我正在使用 boost.asio 编写应用程序。我有一个 boost::asio::ip::tcp::socket 类型的对象,并且(当然)我有 boost::asio::io_context,其中 run 的函数仅从一个线程调用。将数据写入套接字有几种方法,但目前我使用套接字的函数async_write_some,类似于下面的代码:

void tcp_connection::write(packet_ptr packet)
{
    m_socket.async_write_some(boost::asio::buffer(packet->data(), packet->size()),
                              std::bind(&tcp_connection::on_write, this, std::placeholders::_1, std::placeholders::_2, packet));
}

boost::asio 命名空间中还有另一个函数 - async_writeasync_write 的文档说:

This operation is implemented in terms of zero or more calls to the stream's async_write_some function, and is known as a composed operation. The program must ensure that the stream performs no other write operations (such as async_write, the stream's async_write_some function, or any other composed operations that perform writes) until this operation completes.

async_write_some的文档中没有这种'caution'。

这让我有点困惑,我有以下问题:

  1. 在不等待上一个调用完成的情况下调用 async_write_some 是否安全?据我从 boost 的文档中了解到,我不应该用 async_write 这样做,但是 async_write_some 呢?
  2. 如果是,数据写入socket的顺序和调用函数的顺序一样吗?我的意思是如果我调用 async_write_some(packet1)async_write_some(packet2) - 数据包是否会以相同的顺序写入套接字?
  3. 我应该使用哪个功能?它们有什么区别?
  4. 在上一个还没有完成的情况下调用async_write不安全的原因是什么?
  1. 否;其原因可能已记录在底层套接字中 API (BSD/WinSock).

  2. 不适用。请注意,调用处理程序的顺序 保证匹配它们发布的顺序,因此您可以使用完成的 async_write_some 调用的异步链来解决它处理程序发布下一个写入。这被称为隐式链(参见 https://www.boost.org/doc/libs/master/doc/html/boost_asio/overview/core/async.html and Why do I need strand per connection when using boost::asio?)。

  3. 99% 的时间,使用免费功能。不同之处在于它实现了组合操作来发送一个“单元”的信息,即整个缓冲区、消息,或者直到满足给定的完成条件。

    async_write_some 是最低级别的构建块,它甚至不能保证写入所有数据:remarks:

    The write operation may not transmit all of the data to the peer. Consider using the async_write function if you need to ensure that all data is written before the asynchronous operation completes.

  4. 从最严格的意义上讲,这并不是不安全的¹。它只是不会导致正确的结果:这是因为调用处理程序的顺序导致数据以混合顺序写入套接字。


¹(除非您在不同步的情况下并发访问共享 IO 对象)