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:

    1. void handler(
    2. const boost::system::error_code& error, // Result of operation.
    3. std::size_t bytes_transferred // Number of bytes processed.
    4. )

    There is a simple client/server example. Below is client code:

    1. #include <boost/asio.hpp>
    2. #include <functional>
    3. #include <iostream>
    4. #include <memory>
    5. void callback(
    6. const boost::system::error_code& error,
    7. std::size_t bytes_transferred,
    8. std::shared_ptr<boost::asio::ip::tcp::socket> socket,
    9. std::string str)
    10. {
    11. if (error)
    12. {
    13. std::cout << error.message() << '\n';
    14. }
    15. else if (bytes_transferred == str.length())
    16. {
    17. std::cout << "Message is sent successfully!" << '\n';
    18. }
    19. else
    20. {
    21. socket->async_send(
    22. boost::asio::buffer(str.c_str() + bytes_transferred, str.length() - bytes_transferred),
    23. std::bind(callback, std::placeholders::_1, std::placeholders::_2, socket, str));
    24. }
    25. }
    26. int main()
    27. {
    28. try
    29. {
    30. boost::asio::io_context io_context;
    31. boost::asio::ip::tcp::endpoint endpoint{
    32. boost::asio::ip::make_address("192.168.35.145"),
    33. 3303};
    34. std::cout << "Connect to " << endpoint << " successfully!\n";
    35. std::string str{"Hello world!"};
    36. socket->async_send(
    37. boost::asio::buffer(str),
    38. std::bind(callback, std::placeholders::_1, std::placeholders::_2, socket, str));
    39. socket->get_executor().context().run();
    40. }
    41. catch (std::exception& e)
    42. {
    43. std::cerr << e.what() << '\n';
    44. return -1;
    45. }
    46. return 0;
    47. }

    Let’s go through the code:

    (1) Since socket object is non-copyable (please refer socket), socket is created as an shared pointer:

    1. ......
    2. std::bind(callback, std::placeholders::_1, std::placeholders::_2, socket, str)
    3. ......

    (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:

    1. ......
    2. if (error)
    3. {
    4. ......
    5. }
    6. else if (bytes_transferred == str.length())
    7. {
    8. ......
    9. }
    10. else
    11. {
    12. socket->async_send(......);
    13. }

    (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:

    1. #include <ctime>
    2. #include <functional>
    3. #include <iostream>
    4. #include <string>
    5. #include <boost/asio.hpp>
    6. const boost::system::error_code& error,
    7. char recv_str[]) {
    8. if (error)
    9. {
    10. std::cout << error.message() << '\n';
    11. }
    12. else
    13. {
    14. std::cout << recv_str << '\n';
    15. }
    16. }
    17. int main()
    18. {
    19. try
    20. {
    21. boost::asio::io_context io_context;
    22. boost::asio::ip::tcp::acceptor acceptor(
    23. io_context,
    24. boost::asio::ip::tcp::endpoint(boost::asio::ip::tcp::v4(), 3303));
    25. for (;;)
    26. {
    27. boost::asio::ip::tcp::socket socket(io_context);
    28. acceptor.accept(socket);
    29. char recv_str[1024] = {};
    30. socket.async_receive(
    31. boost::asio::buffer(recv_str),
    32. std::bind(callback, std::placeholders::_1, std::placeholders::_2, recv_str));
    33. socket.get_executor().context().run();
    34. socket.get_executor().context().restart();
    35. }
    36. }
    37. catch (std::exception& e)
    38. {
    39. std::cerr << e.what() << std::endl;
    40. }
    41. return 0;
    42. }

    (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:

    1. $ ./client
    2. Message is sent successfully!

    Server outputs following: