boost::asio::async_write_some - sequential function call

Viewed 213

I am writing an application using boost.asio. I've an object of type boost::asio::ip::tcp::socket and (of course) I've boost::asio::io_context which run's function was called from only one thread. For writing data to the socket there are a couple of ways but currently I use socket's function async_write_some, something like the code below:

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));
}

There is another function in boost::asio namespace - async_write. And the documentation of async_write says:

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.

In async_write_some's documentation there is no such kind of 'caution'.

That's a little bit confusing to me and here I've got the following questions:

  1. Is it safe to call async_write_some without waiting for the previous call to be finished? As far as I understood from boost's documentation I shouldn't do that with async_write, but what about async_write_some?
  2. If yes, is the order in which the data is written to the socket the same as the functions were called? I mean if I called async_write_some(packet1) and async_write_some(packet2) - are the packets going to be written to the socket in the same order?
  3. Which function I should use? What is the difference between them?
  4. What is the reason that it's not safe to call async_write while the previous one hasn't finished yet?
1 Answers
  1. no; the reason for that is probably documented with the underlying sockets API (BSD/WinSock).

  2. not applicable. Note that the order in which handlers are invoked is guaranteed to match the order in which they were posted, so you could solve it using an async chain of async_write_some calls where the completion handler posts the next write. This is known as an implicit strand (see 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% of the time, use the free function. The difference is that it implements composed operation to send a "unit" of information, i.e. an entire buffer, message, or until a given completion condition is met.

    async_write_some is the lowest-level building block, which doesn't even guarantee to write all of the data: 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. It's not unsafe¹ in the strictest sense. It just will not lead to correct results: this is because the order in which handlers are invoked leads to data being written to the socket in mixed-up order.


¹(unless you access the shared IO objects concurrently without synchronization)

Related