Asynchronous read/write operations
Since async_send
and async_receive
functions will return immediately, and not block current thread, you should pass a callback function as the parameter which receives the result of read/write operations:
void handler(
const boost::system::error_code& error, // Result of operation.
std::size_t bytes_transferred // Number of bytes processed.
)
There is a simple client/server example. Below is client code:
#include <boost/asio.hpp>
#include <functional>
#include <iostream>
#include <memory>
void callback(
const boost::system::error_code& error,
std::size_t bytes_transferred,
std::shared_ptr<boost::asio::ip::tcp::socket> socket,
std::string str)
{
if (error)
{
std::cout << error.message() << '\n';
}
else if (bytes_transferred == str.length())
{
std::cout << "Message is sent successfully!" << '\n';
}
else
{
socket->async_send(
boost::asio::buffer(str.c_str() + bytes_transferred, str.length() - bytes_transferred),
std::bind(callback, std::placeholders::_1, std::placeholders::_2, socket, str));
}
}
int main()
{
try
{
boost::asio::io_context io_context;
boost::asio::ip::tcp::endpoint endpoint{
boost::asio::ip::make_address("192.168.35.145"),
3303};
std::cout << "Connect to " << endpoint << " successfully!\n";
std::string str{"Hello world!"};
socket->async_send(
boost::asio::buffer(str),
std::bind(callback, std::placeholders::_1, std::placeholders::_2, socket, str));
socket->get_executor().context().run();
}
catch (std::exception& e)
{
std::cerr << e.what() << '\n';
return -1;
}
return 0;
}
Let’s go through the code:
(1) Since socket object is non-copyable (please refer socket), socket is created as an shared pointer:
......
std::bind(callback, std::placeholders::_1, std::placeholders::_2, socket, str)
......
(3) async_send
does not guarantee all the bytes are sent (boost::asio::async_write
returns either all bytes are sent successfully or an error occurs), so needs to reissue async_send
in callback:
......
if (error)
{
......
}
else if (bytes_transferred == str.length())
{
......
}
else
{
socket->async_send(......);
}
(4) io_context.run
function will block until all work has finished and there are no
more handlers to be dispatched, or until the io_context
has been stopped:
If there is no io_context.run
function, the program will exit immediately.
Check the server code who uses async_receive
:
#include <ctime>
#include <functional>
#include <iostream>
#include <string>
#include <boost/asio.hpp>
const boost::system::error_code& error,
char recv_str[]) {
if (error)
{
std::cout << error.message() << '\n';
}
else
{
std::cout << recv_str << '\n';
}
}
int main()
{
try
{
boost::asio::io_context io_context;
boost::asio::ip::tcp::acceptor acceptor(
io_context,
boost::asio::ip::tcp::endpoint(boost::asio::ip::tcp::v4(), 3303));
for (;;)
{
boost::asio::ip::tcp::socket socket(io_context);
acceptor.accept(socket);
char recv_str[1024] = {};
socket.async_receive(
boost::asio::buffer(recv_str),
std::bind(callback, std::placeholders::_1, std::placeholders::_2, recv_str));
socket.get_executor().context().run();
socket.get_executor().context().restart();
}
}
catch (std::exception& e)
{
std::cerr << e.what() << std::endl;
}
return 0;
}
(1) Just for demo purpose: for every client, the callback is called only once;
(2) io_context.restart
must be called to invoke another io_context.run
.
Correspondingly, you can also check how to use boost::asio::async_read
.
Build and run programs. Client outputs following:
$ ./client
Message is sent successfully!
Server outputs following: