WebSockets в C++: Пишем real-time приложение с нуля

Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

Введение: Почему C++ до сих пор рулит в real-time?

Когда речь заходит о real-time приложениях — чатах, биржевых стаканах, многопользовательских играх или системах мониторинга — многие сразу думают о Node.js или Python с asyncio. И зря. C++ остаётся королём производительности и низкой задержки. Если вам нужно обрабатывать тысячи соединений с минимальным latency, WebSockets в C++ — это выбор профессионалов.

В этой статье мы разберём, как поднять real-time сервер на C++, используя мощные библиотеки. Вы узнаете, в чём преимущество C++ перед скриптовыми языками, и получите готовые примеры кода, которые можно сразу использовать в проектах.

Мы не будем ходить вокруг да около: откроем WebSocket-соединение, отправим сообщение и закроем сессию. А заодно посмотрим, как это всё работает под капотом. Поехали!

Что такое WebSocket и почему он нужен в C++?

WebSocket — это протокол, который позволяет установить постоянное двунаправленное соединение между клиентом и сервером. В отличие от HTTP, где каждый запрос — это отдельная транзакция, WebSocket держит «трубу» открытой. Это идеально для real-time приложений C++, где каждая миллисекунда на счету.

Основные сценарии использования:

  • Финансовые терминалы: обновление котировок в реальном времени.
  • Игровые сервера: синхронизация состояния игроков.
  • Системы мониторинга: передача логов и метрик с датчиков.
  • Коллаборативные редакторы: совместное редактирование документов.

C++ даёт здесь неоспоримое преимущество: прямой контроль над памятью, отсутствие GC (сборщика мусора) и возможность использовать асинхронные паттерны без оверхеда виртуальной машины. Если вам нужно обрабатывать 50 000+ одновременных соединений, WebSocket сервер на C++ будет стабильнее и быстрее аналогов.

Выбираем библиотеку: Boost.Beast или uWebSockets?

На рынке C++ есть два основных игрока для работы с WebSocket. Давайте разберём их плюсы и минусы.

Boost.Beast — стандарт индустрии

Boost.Beast — это библиотека на основе Boost.Asio. Она даёт полный контроль над сетевым стеком. Её используют в продакшене такие гиганты, как Facebook (в некоторых внутренних инструментах) и финансовые компании.

  • Плюсы: максимальная гибкость, поддержка HTTP+WebSocket, интеграция с Asio.
  • Минусы: высокий порог входа, много кода для простых задач.

uWebSockets — лёгкость и скорость

uWebSockets (uWS) — это обёртка над C-библиотекой uSockets. Она спроектирована для максимальной производительности и минимального потребления памяти. Идеально для микросервисов.

  • Плюсы: очень быстрый, простой API, низкое потребление RAM.
  • Минусы: меньше сообщество, сложнее кастомизировать.

Для нашего примера мы возьмём Boost.Beast, так как он даёт больше возможностей для обучения. Но если вам нужно простое real-time приложение на C++ под нагрузкой — присмотритесь к uWS.

Пишем простой WebSocket сервер на C++ с Boost.Beast

Давайте создадим минимальный эхо-сервер. Он будет принимать соединения, читать сообщения и отправлять их обратно. Это классический «Hello World» для WebSocket.

Убедитесь, что у вас установлен Boost (желательно версии 1.75+) и компилятор с поддержкой C++17.

#include <boost/beast/core.hpp>
#include <boost/beast/websocket.hpp>
#include <boost/asio/ip/tcp.hpp>
#include <cstdlib>
#include <functional>
#include <iostream>
#include <string>
#include <thread>

namespace beast = boost::beast;
namespace websocket = beast::websocket;
namespace net = boost::asio;
using tcp = net::ip::tcp;

// Обработка одного WebSocket-соединения
void do_session(tcp::socket& socket) {
    try {
        websocket::stream<tcp::socket&> ws{socket};
        ws.accept();

        for (;;) {
            beast::flat_buffer buffer;
            ws.read(buffer);

            // Отправляем обратно то, что получили
            ws.text(ws.got_text());
            ws.write(buffer.data());
        }
    } catch (beast::system_error const& se) {
        if (se.code() != websocket::error::closed) {
            std::cerr << "Error: " << se.code().message() << std::endl;
        }
    }
}

int main() {
    try {
        net::io_context ioc{1};
        tcp::acceptor acceptor{ioc, tcp::endpoint(tcp::v4(), 8080)};

        std::cout << "WebSocket сервер запущен на порту 8080" << std::endl;

        for (;;) {
            tcp::socket socket{ioc};
            acceptor.accept(socket);

            // Запускаем обработку в отдельном потоке
            std::thread{std::bind(&do_session, std::move(socket))}.detach();
        }
    } catch (std::exception const& e) {
        std::cerr << "Error: " << e.what() << std::endl;
        return EXIT_FAILURE;
    }
}

Что здесь происходит:

  • Мы создаём TCP-акцептор на порту 8080.
  • При подключении клиента вызывается do_session.
  • Внутри функции мы выполняем ws.accept() — это рукопожатие WebSocket.
  • Затем в бесконечном цикле читаем сообщения и отправляем их обратно.

Этот код — основа для любого WebSocket сервера на C++. Вы можете модифицировать его под свои задачи: добавить парсинг JSON, роутинг или авторизацию.

Создаём WebSocket клиент на C++

Сервер без клиента — как замок без ключа. Давайте напишем простой клиент, который подключается к нашему серверу и отправляет сообщение.

#include <boost/beast/core.hpp>
#include <boost/beast/websocket.hpp>
#include <boost/asio/connect.hpp>
#include <boost/asio/ip/tcp.hpp>
#include <iostream>

namespace beast = boost::beast;
namespace websocket = beast::websocket;
namespace net = boost::asio;
using tcp = net::ip::tcp;

int main() {
    try {
        net::io_context ioc;
        tcp::resolver resolver{ioc};
        websocket::stream<tcp::socket> ws{ioc};

        auto const results = resolver.resolve("127.0.0.1", "8080");
        net::connect(ws.next_layer(), results.begin(), results.end());

        ws.handshake("127.0.0.1:8080", "/");

        ws.write(net::buffer(std::string("Привет,                

Блоги

Рекомендаций по книгам