WebSockets والتواصل الفوري
WebSockets والتواصل الفوري
كل طلب HTTP يتبع نفس الكوريوغرافيا: العميل يسأل، والخادم يجيب، ثم تُغلق الاتصال أو يبقى خاملًا. هذه الدورة من الطلب والاستجابة تؤدي غرضها جيدًا عند جلب صفحة ويب أو إرسال نموذج، لكنها تتحول إلى عائق فور أن يحتاج منتجك إلى دفع البيانات نحو العميل في اللحظة التي يتغير فيها شيء ما — رسالة دردشة جديدة، سعر سهم متحرك، أو حالة لعبة متعددة اللاعبين تتحدث. يحل WebSocket هذه المشكلة تحديدًا بتحويل اتصال HTTP واحد إلى قناة مستمرة كاملة الاتجاهين يمكن لأي طرف أن يرسل فيها رسالة في أي وقت.
مصافحة WebSocket (الترقية)
يبدأ اتصال WebSocket كطلب HTTP/1.1 عادي تمامًا. يرسل العميل ترويسة Upgrade تُعلن نيّته، فيرد الخادم بـ 101 Switching Protocols، ومن تلك اللحظة يُعاد توظيف اتصال TCP الأساسي — يُستبدل إطار HTTP ببروتوكول إطارات WebSocket الخفيف (RFC 6455). لا مصافحة TCP جديدة، ولا إعادة تفاوض TLS؛ الترقية تتم في مكانها.
الأرقام الجوهرية: حجم ترويسة إطار WebSocket هو 2 إلى 14 بايت فقط لكل رسالة، مقارنةً بـ 400–900 بايت من ترويسات HTTP التي ترافق كل طلب استطلاع. عند معدلات رسائل عالية — محطة تداول تستقبل 1000 تحديث سعر في الثانية — هذا الفارق ليس نظريًا بل جوهري تمامًا.
متى يُعدّ التواصل الفوري ضرورة حقيقية؟
ليست كل ميزة "مباشرة" تستوجب WebSockets. قبل اختيار التقنية، حدّد متطلبات الكُمون والتكرار:
- الدردشة والمراسلة — Slack، WhatsApp Web. يتوقع المستخدمون ظهور الرسائل في أقل من ثانية. عدد اتصالات ضخم (ملايين الاتصالات المستمرة)، بمعدل رسائل متوسط لكل مستخدم.
- التحرير التشاركي — Google Docs، Figma. يجب أن تتزامن مواضع المؤشرات وعمليات الدلتا بين جميع المحررين بكُمون يُقاس بعشرات الميليثانية. أي عملية فائتة تُفسد اتساق المستند.
- التداول المباشر وبيانات السوق — Bloomberg Terminal، Robinhood. يمكن أن تصل عروض الأسعار آلاف المرات في الثانية لكل ورقة مالية. أي عبء لكل رسالة HTTP يُصبح محظورًا.
- الألعاب متعددة اللاعبين — مواضع اللاعبين، الصحة، حالة الفيزياء. الكُمون فوق ~100 ميليثانية محسوس ويُدمّر تجربة اللعب.
- لوحات التحكم المباشرة والمراقبة — لوحات Grafana المباشرة، سجلات النشر المتدفقة إلى المتصفح. الخادم يدفع البيانات؛ العميل نادرًا ما يرسل شيئًا. SSE يمكن أن يؤدي الغرض هنا أيضًا.
- الإشعارات — "شُحنت طلبيتك". نادرة، أحادية الاتجاه. تدفق SSE بسيط أو حتى Long Polling يكفي؛ WebSockets الكاملة قد تكون مبالغة.
المعمارية: توسيع نطاق خوادم WebSocket
يمكن لعملية خادم WebSocket واحدة أن تحتفظ بعشرات الآلاف من الاتصالات المتزامنة، لكن الأنظمة الحقيقية تحتاج خوادم متعددة. هذا يُفرز مشكلة أساسية: رسالة أرسلها العميل A (المتصل بالخادم 1) يجب أن تصل إلى العميل B (المتصل بالخادم 2).
الحل المعياري هو بنية Pub/Sub الخلفية — Redis Pub/Sub عادةً أو وسيط رسائل. كل خادم يشترك في القنوات التي تخص عملاءه المتصلين. حين تصل رسالة إلى أي خادم، يُنشرها على الطبقة الخلفية؛ تقوم الطبقة بتوزيعها على جميع الخوادم الأخرى التي تُعيد إيصالها إلى عملائها المستهدفين.
إدارة الاتصالات والنبضات القلبية (Heartbeats)
اتصال TCP المستمر غير مرئي لمعدات الشبكة — تملك جدران الحماية وأجهزة NAT مؤقتات للاتصالات الخاملة، تتراوح عادةً بين 30–300 ثانية، تُسقط الاتصال بصمت بعدها. العميل والخادم يظلان غير مدركَين لذلك حتى يحاول أحدهما إرسال رسالة ولا يتلقى أي إقرار.
الحل هو نبضة قلبية Ping/Pong: يرسل الخادم إطار تحكم Ping عبر WebSocket كل 20–30 ثانية؛ ويُلزم البروتوكول العميلَ بالرد بـ Pong. إن لم يصل Pong خلال نافذة المهلة، يُغلق الخادم الاتصال. العميل، حين يلاحظ الإغلاق، يُطلق إعادة اتصال بتراجع أسي — عادةً يبدأ بثانية واحدة، يتضاعف حتى حد أقصى 30–60 ثانية، مع تشويش عشوائي صغير لتجنب إعادة اتصال آلاف العملاء في آنٍ واحد (مشكلة القطيع المتدافع).
اعتبارات الأمان
يجب دائمًا استخدام wss:// (مشفر بـ TLS، مكافئ HTTPS) لاتصالات WebSocket. مصافحة HTTP الأولية خاضعة لنفس سياسة المصدر الواحد كالطلبات العادية، لكن الاتصال المستمر بعدها لا يخضع لها — بمجرد إنشاء الاتصال، لا يُطبق المتصفح فحوصات المصدر على الإطارات. هذا يعني:
- المصادقة عند الاتصال — تحقق من رمز أو ملف تعريف ارتباط الجلسة خلال طلب ترقية HTTP، قبل فتح WebSocket. لا تعتمد على المصادقة في النطاق لاحقًا.
- التحقق من كل رسالة — عامل رسائل WebSocket الواردة من العملاء كمدخلات غير موثوقة تمامًا كأجسام طلبات HTTP. عقّمها وتحقق منها.
- تحديد معدل الاتصالات والرسائل — عميل يفتح آلاف الاتصالات أو يرسل ملايين الإطارات الصغيرة في الثانية هو ناقل هجوم حجب خدمة. طبّق الحدود في طبقة خادم WS أو البوابة.
wss://api.example.com/ws?token=SECRET — هذا يُسرّب الرمز إلى سجلات الوصول، وسجلات الوكيل، وسجل المتصفح. مرّر الرمز في ملف تعريف ارتباط مُعيَّن أثناء تسجيل الدخول (يُرسل تلقائيًا مع طلب الترقية) أو ضمن إطار الرسالة الأول بعد فتح الاتصال.
WebSockets مقابل البدائل
عمليًا، يقف WebSocket جنبًا إلى جنب مع تقنيتين أخريين لدفع البيانات من الخادم. الاختيار الصحيح يعتمد على نمط حركة البيانات:
- Long Polling — يرسل العميل طلب HTTP؛ يبقي الخادم الطلب مفتوحًا حتى تتوفر بيانات، ثم يستجيب. يرسل العميل فورًا طلبًا جديدًا. يعمل في كل مكان، لكنه عالي الكُمون والعبء، وليس ثنائي الاتجاه حقًا.
- Server-Sent Events (SSE) — تدفق استجابة HTTP طويل الأمد واحد؛ يدفع الخادم أحداثًا نصية محددة بأسطر جديدة. مدعوم أصلًا في المتصفحات، متعدد القنوات في HTTP/2، مثالي للتغذيات أحادية الاتجاه. لا مسار من العميل إلى الخادم.
- WebSockets — كاملة الاتجاهين، إطارات ثنائية أو نصية، عبء منخفض. ضرورية حين يرسل العميل بتكرار (مدخلات الألعاب، تعديلات تشاركية، مؤشرات الكتابة في الدردشة).
الدرس التاسع من هذه السلسلة يغطي المقارنة الكاملة بالتفصيل. حتى ذلك الحين: إن كنت بحاجة إلى تواصل ثنائي الاتجاه بكُمون منخفض وتكرار عالٍ — WebSockets هو الأداة المناسبة.