Boost ASIO is a library for Asynchronous Network Communication. Among them, async_write is a common function. However, if it is not used correctly, unexpected potential bugs may occur. For example, the following code:
for (int i=0; i < n; i++){ boost::asio::async_write( socket_, boost::asio::buffer( buffer[i].data_.get(), buffer[i].length_ ), boost::asio::transfer_at_least(buffer[i].length_), boost::bind( &HttpServer::HandleTcpSend, shared_from_this(), boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred ) ); // Do something}
The code is simple, that is, loop N times and send n buffer blocks. Our goal is to receive buffer1, buffer2 ,......, Buffer n. However, in fact, the above Code is faulty, and the server may receive completely disordered data. Let's take a look at the correct method. The Code is as follows:
int i=0; boost::asio::async_write( socket_, boost::asio::buffer( buffer[i].data_.get(), buffer[i].length_ ), boost::asio::transfer_at_least(buffer[i].length_), boost::bind( &HttpServer::HandleTcpSend, shared_from_this(), boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred ) ); // Do something void HttpServer::HandleTcpSend(const boost::system::error_code& err, size_t bytes_transferred){ i++; boost::asio::async_write( socket_, boost::asio::buffer( buffer[i].data_.get(), buffer[i].length_ ), boost::asio::transfer_at_least(buffer[i].length_), boost::bind( &HttpServer::HandleTcpSend, shared_from_this(), boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred ) );}
Problem. This is not a limitation of ASIO. Some functions of the underlying socket, such as sending, cannot guarantee that all data is sent through the TCP stream in an asynchronous operation. Async_write notifies you of the number of bytes actually sent, and then requires that the remaining bytes be sent in the next asynchronous operation. Async_write is implemented by calling the async_write_some function once or multiple times. If the first async_write is not completed, the second async_write is called, async_write_some may first send the data of the second buffer.
Therefore, never start your second async_write before the first has completed.
From http://www.sizeof.cn/html/2009/143.html