Как асинхронно отправить данные на сервер, используя C++?

«Как асинхронно отправить данные на сервер, используя C++?» — вопрос из категории Сети, который задают на 25% собеседований C/C++ Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

В своих проектах я использовал Boost.Asio для асинхронного сетевого ввода-вывода. Вот пример асинхронной отправки данных по TCP:

#include <boost/asio.hpp>
#include <iostream>

using boost::asio::ip::tcp;

class AsyncSender {
public:
    AsyncSender(boost::asio::io_context& io_context, const std::string& host, const std::string& port)
        : resolver_(io_context), socket_(io_context) {
        connect(host, port);
    }

    void send_data(const std::string& data) {
        // Копируем данные, чтобы они жили до завершения операции
        auto shared_data = std::make_shared<std::string>(data);

        boost::asio::async_write(socket_, boost::asio::buffer(*shared_data),
            [this, shared_data](boost::system::error_code ec, std::size_t length) {
                if (!ec) {
                    std::cout << "Sent " << length << " bytes asynchronously.n";
                } else {
                    std::cerr << "Send failed: " << ec.message() << "n";
                }
            });
    }

private:
    void connect(const std::string& host, const std::string& port) {
        resolver_.async_resolve(host, port,
            [this](const boost::system::error_code& ec, tcp::resolver::results_type endpoints) {
                if (!ec) {
                    boost::asio::async_connect(socket_, endpoints,
                        [this](boost::system::error_code ec, const tcp::endpoint&) {
                            if (!ec) {
                                std::cout << "Connected!n";
                            }
                        });
                }
            });
    }

    tcp::resolver resolver_;
    tcp::socket socket_;
};

// Использование:
// boost::asio::io_context io;
// AsyncSender sender(io, "example.com", "http");
// sender.send_data("POST /data HTTP/1.1rn...");
// io.run(); // Запуск цикла обработки событий

Ключевые моменты:

  • Операция async_write не блокирует вызывающий поток.
  • Завершение операции обрабатывается в лямбда-функции (обратном вызове).
  • Необходимо гарантировать время жизни отправляемых данных до завершения операции (часто используют std::shared_ptr).
  • Для HTTP-запросов можно поверх Asio использовать библиотеки вроде Boost.Beast.