Long polling مقابل WebSocket في C++: معركة الوقت الفعلي
\n\nتخيل: أنت تكتب تطبيق دردشة بلغة C++، أو محطة تداول، أو نظام مراقبة خوادم. يجب أن يتلقى العميل البيانات فوراً. طلبات HTTP "اسأل وأجب" غير مناسبة - بطيئة جداً ومهدرة للموارد. هناك حلان: Long polling (المدرسة القديمة) و WebSocket (المعيار الحديث). ماذا تختار لمشروع C++؟ دعنا نتعرف على ذلك من خلال أمثلة حقيقية.
\n\nكيف يعمل Long polling في C++ (ولماذا لا يزال حياً)
\n\nLong polling هو محاكاة للوقت الفعلي عبر HTTP العادي. يرسل العميل طلباً، ولا يستجيب الخادم فوراً، بل "يعلق" حتى ظهور بيانات جديدة أو انتهاء المهلة. بمجرد ظهور البيانات - يرسل الخادم الرد، ويرسل العميل طلباً جديداً فوراً. يتم إنشاء وهم التدفق المستمر.
\n\nفي C++، غالباً ما يتم تنفيذ هذا الأسلوب باستخدام libcurl على العميل وأي خادم HTTP (مثل cpp-httplib أو Boost.Beast) على الخادم. إليك كيف يبدو الجزء الخادم الكلاسيكي باستخدام Boost.Beast:
#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 // طريقة آمنة للخيوط لإضافة رسالة\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\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 // ننتظر رسالة جديدة أو مهلة 30 ثانية\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 // مهلة - نعيد رداً فارغاً\n res.result(http::status::no_content);\n res.body() = "";\n }\n res.prepare_payload();\n }\n};\n\nالعميل باستخدام libcurl سيبدو كالتالي:
\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); // أكبر قليلاً من مهلة الخادم\n\n CURLcode res = curl_easy_perform(curl);\n if (res == CURLE_OK && !response.empty()) {\n std::cout << "تم الاستلام: " << response << std::endl;\n response.clear();\n // نرسل طلباً جديداً فوراً\n continue;\n }\n // عند حدوث خطأ، ننتظر 5 ثوانٍ ونكرر\n std::this_thread::sleep_for(std::chrono::seconds(5));\n }\n}\n\nإيجابيات Long polling في C++: البساطة، التوافق مع جميع البروكسيات وجدران الحماية، لا يتطلب مكتبات خاصة. السلبيات: عدد كبير من رؤوس HTTP، تأخيرات في إنشاء الاتصال (TCP ha