Long polling vs WebSocket in C++: Kampf um die Echtzeit
\n\nStellen Sie sich vor: Sie schreiben einen Chat in C++, einen Börsenterminal oder ein Server-Überwachungssystem. Der Client muss Daten sofort erhalten. HTTP-Anfragen „fragen-und-antworten“ sind nicht geeignet – zu langsam und verschwenderisch. Es gibt zwei Auswege: Long polling (alte Schule) und WebSocket (moderner Standard). Was für ein C++-Projekt wählen? Lassen Sie es uns anhand realer Beispiele herausfinden.
\n\nWie Long polling in C++ funktioniert (und warum es immer noch lebt)
\n\nLong polling ist eine Echtzeit-Emulation über normales HTTP. Der Client sendet eine Anfrage, der Server antwortet nicht sofort, sondern „hängt“, bis neue Daten erscheinen oder ein Timeout eintritt. Sobald Daten erscheinen, sendet der Server eine Antwort, der Client sendet sofort eine neue Anfrage. Es entsteht die Illusion eines kontinuierlichen Stroms.
\n\nIn C++ wird dieser Ansatz oft mit libcurl auf dem Client und einem beliebigen HTTP-Server (z. B. cpp-httplib oder Boost.Beast) auf dem Server implementiert. So sieht der klassische Serverteil mit Boost.Beast aus:
#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-sichere Methode zum Hinzufügen einer Nachricht\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 Anfrage-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 // Warte auf neue Nachricht oder Timeout von 30 Sekunden\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 – leere Antwort zurückgeben\n res.result(http::status::no_content);\n res.body() = "";\n }\n res.prepare_payload();\n }\n};\n\nDer Client mit libcurl sieht so aus:
\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); // etwas größer als Server-Timeout\n\n CURLcode res = curl_easy_perform(curl);\n if (res == CURLE_OK && !response.empty()) {\n std::cout << "Erhalten: " << response << std::endl;\n response.clear();\n // sofort neue Anfrage senden\n continue;\n }\n // Bei Fehler 5 Sekunden warten und wiederholen\n std::this_thread::sleep_for(std::chrono::seconds(5));\n }\n}\n\nVorteile von Long polling in C++: Einfachheit, Kompatibilität mit allen Proxys und Firewalls, erfordert keine speziellen Bibliotheken. Nachteile: Riesige Menge an HTTP-Headern, Verzögerungen beim Verbindungsaufbau (TCP ha