Server-Sent Events в C++: Реалтайм без магии и лишних библиотек

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

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

Начать курс

Почему обычный HTTP-запрос — это как письмо по почте, а SSE — телеграмма в реальном времени

Представьте: вы ждёте уведомление о новом комментарии на сайте. Вы обновляете страницу каждые 5 секунд. Сервер каждый раз возвращает кучу HTML, CSS, картинок — и только потом, в самом низу, вы видите: «Новых комментариев нет». Знакомо? Это называется polling. Работает, но жрёт трафик и грузит сервер.

А теперь представьте другой сценарий: вы открыли страницу, и через секунду на ней появляется сообщение: «Василий оставил комментарий: "Классная статья!"». Без перезагрузки, без лишних запросов. Сервер сам «толкает» вам данные. Это и есть Server-Sent Events (SSE) — технология, которая позволяет серверу отправлять клиенту поток событий через обычное HTTP-соединение.

В этой статье мы разберём, как реализовать SSE на чистом C++ без использования тяжёлых фреймворков. Вы узнаете, почему Server-Sent Events в C++ — это отличный выбор для мониторинга, биржевых котировок, чат-уведомлений и любых задач, где нужна односторонняя передача данных в реальном времени.

Как работают Server-Sent Events? Разбор протокола

SSE — это часть спецификации HTML5. Клиент открывает обычное HTTP-соединение и говорит серверу: «Я готов слушать события». Сервер в ответ не закрывает соединение, а начинает отправлять данные в специальном формате text/event-stream.

Формат сообщения предельно простой:

data: Это текст события\n\n

Каждое событие начинается с data: и заканчивается двойным переносом строки. Можно добавить id: для идентификации, event: для типа события и retry: для указания времени переподключения в миллисекундах.

Пример полноценного потока:

id: 42
event: new_message
data: {"user": "Василий", "text": "Привет!"}

id: 43
event: ping
data: Сервер жив

Клиент (браузер или любое приложение) обрабатывает эти строки и генерирует JavaScript-события. Всё гениальное — просто.

SSE vs WebSocket: когда что выбирать?

Многие сразу думают о WebSocket, когда речь заходит о реалтайме. Давайте сравним:

  • WebSocket — двусторонняя связь. Клиент и сервер могут инициировать обмен. Требует отдельного протокола (ws://), прохождения через прокси, часто блокируется корпоративными файрволами.
  • SSE — односторонняя связь (сервер → клиент). Работает поверх обычного HTTP. Автоматически переподключается при разрыве. Легко проходит через любые прокси.

Если ваша задача — отправлять уведомления клиенту, а не ждать от него команд, Server-Sent Events на C++ — это элегантное и простое решение. Не нужно тащить тяжелые библиотеки, не нужно писать сложные хендлеры.

Пишем SSE-сервер на C++ с нуля

Для реализации нам понадобится минимум: сокеты и работа с HTTP. В реальных проектах используют Boost.Beast или libmicrohttpd, но для понимания сути мы напишем простой сервер на чистом C++ с использованием POSIX-сокетов.

Наш сервер будет:

  • Принимать HTTP-запрос от клиента
  • Определять, что клиент хочет SSE (по заголовку Accept: text/event-stream)
  • Отправлять поток событий с текущим временем каждые 2 секунды

Шаг 1: Создаём сокет и слушаем порт

#include <iostream>
#include <string>
#include <cstring>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <thread>
#include <chrono>
#include <sstream>

void handle_client(int client_socket) {
    // Буфер для запроса
    char buffer[4096] = {0};
    read(client_socket, buffer, 4096);
    
    // Проверяем, что это GET запрос с Accept: text/event-stream
    std::string request(buffer);
    if (request.find("GET /events") == std::string::npos) {
        // Отправляем простой ответ для других запросов
        std::string response = "HTTP/1.1 200 OK\r\nContent-Type: text/plain\r\n\r\nServer is running";
        send(client_socket, response.c_str(), response.size(), 0);
        close(client_socket);
        return;
    }

    // Отправляем SSE-заголовки
    std::string headers = 
        "HTTP/1.1 200 OK\r\n"
        "Content-Type: text/event-stream\r\n"
        "Cache-Control: no-cache\r\n"
        "Connection: keep-alive\r\n"
        "Access-Control-Allow-Origin: *\r\n"
        "\r\n";
    
    send(client_socket, headers.c_str(), headers.size(), 0);

    // Отправляем события каждые 2 секунды
    int event_id = 0;
    while (true) {
        std::stringstream ss;
        ss << "id: " << event_id++ << "\n";
        ss << "event: time_update\n";
        ss << "data: {\"time\": \"" 
           << std::chrono::system_clock::to_time_t(std::chrono::system_clock::now()) 
           << "\"}\n\n";
        
        std::string event = ss.str();
        
        if (send(client_socket, event.c_str(), event.size(), 0) < 0) {
            // Соединение разорвано или ошибка
            break;
        }
        
        std::this_thread::sleep_for(std::chrono::seconds(2));
    }
    
    close(client_socket);
}

int main() {
    int server_fd = socket(AF_INET, SOCK_STREAM, 0);
    
    sockaddr_in address;
    address.sin_family = AF_INET;
    address.sin_addr.s_addr = INADDR_ANY;
    address.sin_port = htons(8080);
    
    bind(server_fd, (sockaddr*)&address, sizeof(address));
    listen(server_fd, 3);
    
    std::cout << "SSE Server started on port 8080" << std::endl;
    
    while (true) {
        int client_socket = accept(server_fd, nullptr, nullptr);
        std::thread(handle_client, client_socket).detach();
    }
    
    close(server_fd);
    return 0;
}

Этот код — минимальная, но рабочая реализация SSE сервера на C++. Запустите его, откройте браузер на http://localhost:8080/events — и вы увидите поток событий.

Шаг 2: Клиентская часть (HTML + JavaScript)

Чтобы протестировать сервер, создайте простую HTML-страницу:

<!DOCTYPE html>
<html>
<head>
    &                

Блоги

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