Long polling vs WebSocket in C++: What to Choose for Real-Time

Online Python Trainer for Beginners

Learn Python easily without overwhelming theory. Solve practical tasks with automatic checking, get hints in Russian, and write code directly in your browser — no installation required.

Start Course

Long polling vs WebSocket in C++: The Battle for Real-Time

\n\n

Imagine: you are writing a chat in C++, a stock exchange terminal, or a server monitoring system. The client must receive data instantly. HTTP "request-response" requests are not suitable — too slow and wasteful. There are two options: Long polling (old school) and WebSocket (modern standard). What to choose for a C++ project? Let's figure it out with real examples.

\n\n

How Long Polling Works in C++ (and Why It's Still Alive)

\n\n

Long polling is an emulation of real-time over regular HTTP. The client sends a request, the server does not respond immediately, but "hangs" until new data appears or a timeout occurs. As soon as data appears — the server sends a response, the client immediately sends a new request. An illusion of a continuous stream is created.

\n\n

In C++, this approach is often implemented via libcurl on the client and any HTTP server (e.g., cpp-httplib or Boost.Beast) on the server. Here is what a classic server-side part looks like on Boost.Beast:

\n\n
#include <boost/beast/core.hpp>\n#include <boost/beast/http.hpp>\n#include <boost/beast/version.hpp>\n#include <boost/asio.hpp>\n#include <queue>\n#include <mutex>\n#include <condition_variable>\n\nnamespace beast = boost::beast;\nnamespace http = beast::http;\nnamespace net = boost::asio;\n\nclass LongPollHandler {\n    std::queue<std::string> messages_;\n    std::mutex mtx_;\n    std::condition_variable cv_;\npublic:\n    // Thread-safe method for adding a message\n    void push(const std::string& msg) {\n        std::lock_guard<std::mutex> lock(mtx_);\n        messages_.push(msg);\n        cv_.notify_one();\n    }\n\n    // Long Polling request handler\n    void handle(http::request<http::string_body>& req,\n                http::response<http::string_body>& res) {\n        std::unique_lock<std::mutex> lock(mtx_);\n        // Wait for a new message or a 30-second timeout\n        if (cv_.wait_for(lock, std::chrono::seconds(30),\n                         [this](){ return !messages_.empty(); })) {\n            std::string msg = messages_.front();\n            messages_.pop();\n            res.result(http::status::ok);\n            res.body() = msg;\n        } else {\n            // Timeout — return an empty response\n            res.result(http::status::no_content);\n            res.body() = "";\n        }\n        res.prepare_payload();\n    }\n};
\n\n

The client on libcurl will look like this:

\n\n
#include <curl/curl.h>\n#include <string>\n#include <iostream>\n\nsize_t write_callback(void* contents, size_t size, size_t nmemb, void* userp) {\n    ((std::string*)userp)->append((char*)contents, size * nmemb);\n    return size * nmemb;\n}\n\nvoid long_poll_loop(CURL* curl, const std::string& url) {\n    std::string response;\n    while (true) {\n        curl_easy_setopt(curl, CURLOPT_URL, url.c_str());\n        curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_callback);\n        curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response);\n        curl_easy_setopt(curl, CURLOPT_TIMEOUT, 35L); // slightly more than the server timeout\n\n        CURLcode res = curl_easy_perform(curl);\n        if (res == CURLE_OK && !response.empty()) {\n            std::cout << "Received: " << response << std::endl;\n            response.clear();\n            // immediately send a new request\n            continue;\n        }\n        // On error, wait 5 seconds and retry\n        std::this_thread::sleep_for(std::chrono::seconds(5));\n    }\n}
\n\n

Pros of Long polling in C++: Simplicity, compatibility with all proxies and firewalls, no special libraries required. Cons: Huge number of HTTP headers, connection setup delays (TCP ha

Blogs

Book Recommendations