Long polling vs WebSocket 在 C++ 中:实时通信之争
想象一下:您正在用 C++ 编写一个聊天程序、股票交易终端或服务器监控系统。客户端需要即时接收数据。HTTP 的“请求-响应”模式并不适用——太慢且浪费资源。有两种方案:Long polling(传统方式)和 WebSocket(现代标准)。对于 C++ 项目,该如何选择?让我们通过实际示例来探讨。
Long polling 在 C++ 中如何工作(以及它为何至今仍被使用)
Long polling 是一种在普通 HTTP 之上模拟实时通信的技术。客户端发送请求,服务器不会立即响应,而是“挂起”直到有新数据到达或超时。一旦有数据,服务器便发送响应,客户端则立即发送新请求。这样就营造出一种连续数据流的假象。
在 C++ 中,这种方案通常通过客户端上的 libcurl 和服务器上的任意 HTTP 服务器(例如 cpp-httplib 或 Boost.Beast)来实现。以下是基于 Boost.Beast 的经典服务器端代码:
#include <boost/beast/core.hpp>#include <boost/beast/http.hpp>#include <boost/beast/version.hpp>#include <boost/asio.hpp>#include <queue>#include <mutex>#include <condition_variable>
namespace beast = boost::beast;namespace http = beast::http;namespace net = boost::asio;
class LongPollHandler { std::queue<std::string> messages_; std::mutex mtx_; std::condition_variable cv_;public: // 线程安全的消息添加方法 void push(const std::string& msg) { std::lock_guard<std::mutex> lock(mtx_); messages_.push(msg); cv_.notify_one(); }
// Long Polling 请求处理器 void handle(http::request<http::string_body>& req, http::response<http::string_body>& res) { std::unique_lock<std::mutex> lock(mtx_); // 等待新消息或 30 秒超时 if (cv_.wait_for(lock, std::chrono::seconds(30), [this](){ return !messages_.empty(); })) { std::string msg = messages_.front(); messages_.pop(); res.result(http::status::ok); res.body() = msg; } else { // 超时——返回空响应 res.result(http::status::no_content); res.body() = ""; } res.prepare_payload(); }};基于 libcurl 的客户端代码如下:
#include <curl/curl.h>#include <string>#include <iostream>
size_t write_callback(void* contents, size_t size, size_t nmemb, void* userp) { ((std::string*)userp)->append((char*)contents, size * nmemb); return size * nmemb;}
void long_poll_loop(CURL* curl, const std::string& url) { std::string response; while (true) { curl_easy_setopt(curl, CURLOPT_URL, url.c_str()); curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_callback); curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response); curl_easy_setopt(curl, CURLOPT_TIMEOUT, 35L); // 略大于服务器超时时间
CURLcode res = curl_easy_perform(curl); if (res == CURLE_OK && !response.empty()) { std::cout << "收到: " << response << std::endl; response.clear(); // 立即发送新请求 continue; } // 出错时等待 5 秒后重试 std::this_thread::sleep_for(std::chrono::seconds(5)); }}Long polling 在 C++ 中的优点: 简单、兼容所有代理和防火墙、无需特殊库。缺点: 大量的 HTTP 头部开销、建立连接时的延迟(TCP 握