WebSockets والتطبيقات الفورية

فهم بروتوكول WebSocket

20 دقيقة الدرس 2 من 35

بروتوكول WebSocket

WebSocket هو بروتوكول اتصال معرف في RFC 6455 يوفر قنوات اتصال كاملة الازدواج عبر اتصال TCP واحد. على عكس HTTP، الذي يتبع نمط طلب-استجابة، يتيح WebSocket تدفق بيانات ثنائي الاتجاه مستمر بين العميل والخادم.

المواصفات الرئيسية: تم توحيد بروتوكول WebSocket من قبل IETF كـ RFC 6455 في عام 2011 ومدعوم من قبل معيار WHATWG HTML Living Standard. يعمل على المنافذ 80 (ws://) و 443 (wss://) للعمل من خلال جدران الحماية والوكلاء.

مصافحة WebSocket

تبدأ اتصالات WebSocket كطلبات HTTP ثم "تُرقى" إلى بروتوكول WebSocket من خلال عملية مصافحة:

طلب مصافحة العميل

GET /chat HTTP/1.1 Host: example.com:8080 Upgrade: websocket Connection: Upgrade Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ== Sec-WebSocket-Version: 13 Origin: http://example.com

شرح الرؤوس الرئيسية:

  • Upgrade: websocket - يطلب ترقية البروتوكول من HTTP إلى WebSocket
  • Connection: Upgrade - يشير إلى أن العميل يريد تغيير البروتوكولات
  • Sec-WebSocket-Key - قيمة عشوائية مشفرة بـ Base64 من 16 بايت للأمان
  • Sec-WebSocket-Version - إصدار بروتوكول WebSocket (13 هو الحالي)
  • Origin - رأس أمان المتصفح يشير إلى أصل الطلب

استجابة مصافحة الخادم

HTTP/1.1 101 Switching Protocols Upgrade: websocket Connection: Upgrade Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=

تفاصيل الاستجابة:

  • 101 Switching Protocols - رمز الحالة الذي يشير إلى ترقية ناجحة
  • Sec-WebSocket-Accept - تجزئة محسوبة لمفتاح العميل تثبت أن الخادم يفهم بروتوكول WebSocket
آلية الأمان: يتم حساب رأس Sec-WebSocket-Accept من خلال دمج Sec-WebSocket-Key للعميل مع السلسلة السحرية "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"، ثم أخذ تجزئة SHA-1 وترميزها بـ Base64. هذا يمنع هجمات الخلط بين البروتوكولات.

عناوين URI لـ WebSocket: ws:// و wss://

يستخدم WebSocket مخططات URI الخاصة به مماثلة لـ HTTP:

// اتصال WebSocket غير مشفر ws://example.com:8080/socket // اتصال WebSocket مشفر (عبر TLS/SSL) wss://example.com:443/socket

مكونات URI:

  • المخطط: ws:// (غير مشفر) أو wss:// (مشفر)
  • المضيف: اسم النطاق أو عنوان IP
  • المنفذ: 80 لـ ws://، 443 لـ wss:// (يمكن أن يكون مخصصًا)
  • المسار: مسار المورد على الخادم
  • الاستعلام: معلمات استعلام اختيارية (مثل ?token=abc123)
أفضل ممارسة أمنية: استخدم دائمًا wss:// في الإنتاج! اتصالات ws:// غير المشفرة تعرض جميع البيانات للتنصت وهجمات الرجل في الوسط. تحظر العديد من المتصفحات اتصالات ws:// من صفحات HTTPS.

بنية إطار WebSocket

بعد المصافحة، يحدث كل الاتصال من خلال إطارات WebSocket. كل إطار له بنية رأس بسيطة للكفاءة:

0 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +-+-+-+-+-------+-+-------------+-------------------------------+ |F|R|R|R| opcode|M| Payload len | Extended payload length | |I|S|S|S| (4) |A| (7) | (16/64) | |N|V|V|V| |S| | (if payload len==126/127) | | |1|2|3| |K| | | +-+-+-+-+-------+-+-------------+ - - - - - - - - - - - - - - - + | Extended payload length continued, if payload len == 127 | + - - - - - - - - - - - - - - - +-------------------------------+ | |Masking-key, if MASK set to 1 | +-------------------------------+-------------------------------+ | Masking-key (continued) | Payload Data | +-------------------------------- - - - - - - - - - - - - - - - + : Payload Data continued ... : + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + | Payload Data continued ... | +---------------------------------------------------------------+

مكونات رأس الإطار:

  • FIN (1 بت): يشير إلى ما إذا كان هذا هو الجزء الأخير (1) أو المزيد من الأجزاء قادمة (0)
  • RSV1-3 (3 بتات): محجوز للامتدادات، يجب أن يكون 0
  • Opcode (4 بتات): نوع الإطار (نص، ثنائي، إغلاق، ping، pong)
  • MASK (1 بت): ما إذا كان الحمل مقنعًا (مطلوب من العميل إلى الخادم)
  • Payload length (7 بتات + ممتد): طول بيانات الحمل
  • Masking-key (32 بت): مفتاح عشوائي يستخدم لإخفاء الحمل (من العميل إلى الخادم فقط)

أكواد العمليات للإطار

الكود | المعنى | الوصف --------|------------------|---------------------------------- 0x0 | استمرار | إطار استمرار 0x1 | نص | بيانات نصية UTF-8 0x2 | ثنائي | بيانات ثنائية 0x8 | إغلاق | إغلاق الاتصال 0x9 | Ping | نبضة قلب ping 0xA | Pong | استجابة نبضة قلب pong
إخفاء من العميل إلى الخادم: يجب أن يتم إخفاء جميع الإطارات المرسلة من العميل إلى الخادم بمفتاح عشوائي 32 بت. هذا يمنع هجمات تسميم ذاكرة التخزين المؤقت حيث يمكن تفسير بيانات WebSocket الضارة على أنها HTTP بواسطة خوادم الوكيل. لا يتم إخفاء الإطارات من الخادم إلى العميل.

دورة حياة الاتصال

يمر اتصال WebSocket بعدة مراحل متميزة:

1. الاتصال (CONNECTING)

الحالة الأولية عند استدعاء منشئ WebSocket ولكن المصافحة لم تكتمل بعد.

const socket = new WebSocket('wss://example.com/socket'); console.log(socket.readyState); // 0 - CONNECTING

2. مفتوح (OPEN)

نجحت المصافحة وتم إنشاء الاتصال. يمكن الآن إرسال واستقبال البيانات.

socket.onopen = (event) => { console.log('تم إنشاء الاتصال'); console.log(socket.readyState); // 1 - OPEN socket.send('مرحبًا!'); };

3. الإغلاق (CLOSING)

بدأ أي من الطرفين مصافحة الإغلاق ولكن الاتصال لم يُغلق بعد.

socket.close(1000, 'إغلاق عادي'); console.log(socket.readyState); // 2 - CLOSING

4. مغلق (CLOSED)

تم إغلاق الاتصال أو لم يمكن إنشاؤه.

socket.onclose = (event) => { console.log('تم إغلاق الاتصال'); console.log(socket.readyState); // 3 - CLOSED console.log('الكود:', event.code); console.log('السبب:', event.reason); };

أكواد حالة الإغلاق

عند إغلاق اتصال WebSocket، يمكن توفير كود حالة وسبب اختياري:

الكود | الاسم | الوصف ------|----------------------|---------------------------------------- 1000 | إغلاق عادي | عملية ناجحة / إغلاق عادي 1001 | المغادرة | نقطة النهاية تغادر (الخادم معطل، التنقل في الصفحة) 1002 | خطأ في البروتوكول | نقطة النهاية تنتهي بسبب خطأ في البروتوكول 1003 | بيانات غير مدعومة | لا يمكن قبول نوع البيانات 1006 | إغلاق غير طبيعي | لم يتم استلام إطار إغلاق (محجوز، لا يمكن إرساله) 1007 | حمل غير صالح | بيانات غير متسقة (مثل non-UTF8 في إطار نصي) 1008 | انتهاك السياسة | الرسالة تنتهك السياسة 1009 | رسالة كبيرة جدًا | الرسالة كبيرة جدًا للمعالجة 1010 | امتداد إلزامي | توقع العميل أن يتفاوض الخادم على الامتداد 1011 | خطأ داخلي في الخادم | حالة غير متوقعة منعت التنفيذ 1015 | مصافحة TLS | فشل مصافحة TLS (محجوز، لا يمكن إرساله)
إغلاق نظيف: أغلق دائمًا الاتصالات بكود الحالة 1000 وسبب وصفي عند الإغلاق بشكل طبيعي. هذا يساعد في تصحيح الأخطاء ويوفر تجربة مستخدم أفضل.

WebSocket مقابل HTTP: الاختلافات الرئيسية

نموذج الاتصال

HTTP: - طلب ← استجابة ← إغلاق - اتصالات قصيرة الأمد - يجب أن يبدأ العميل كل الاتصال WebSocket: - مصافحة ← اتصال مستمر - قناة ثنائية الاتجاه طويلة الأمد - يمكن لكلا الطرفين الإرسال في أي وقت

مقارنة الحمل

طلب HTTP: - الرؤوس: 200-2000+ بايت لكل طلب - كل طلب يتضمن رؤوسًا كاملة إطار WebSocket: - الرؤوس: 2-14 بايت لكل رسالة - يتم إنشاء الاتصال مرة واحدة - تخفيض 99٪ في الحمل للرسائل الصغيرة

التأخير

HTTP: كل رسالة تتطلب مصافحة TCP (إذا تم إغلاق الاتصال)، مصافحة TLS (HTTPS)، ومعالجة رؤوس HTTP.

WebSocket: بعد المصافحة الأولية، تحتوي الرسائل على حمل تأطير ضئيل وبدون مصافحات إضافية.

تمرين: احسب توفير النطاق الترددي لـ WebSocket مقابل HTTP لتطبيق دردشة يرسل 100 رسالة قصيرة في الدقيقة:
  • HTTP: ~150KB رؤوس + بيانات الرسالة في الدقيقة
  • WebSocket: ~1KB تأطير + بيانات الرسالة في الدقيقة
  • التوفير: ~99٪ تخفيض في الحمل

دعم المتصفح

يتم دعم WebSocket من قبل جميع المتصفحات الحديثة:

المتصفح | الإصدار | السنة -----------------|---------|------ Chrome | 16+ | 2012 Firefox | 11+ | 2012 Safari | 7+ | 2013 Edge | All | 2015 Opera | 12.1+ | 2012 Mobile Safari | 7.1+ | 2014 Chrome Android | All | 2012+
اكتشاف الميزة: تحقق من دعم WebSocket قبل الاستخدام:

if ('WebSocket' in window) {
  // WebSocket مدعوم
} else {
  // الرجوع إلى الاستقصاء أو SSE
}

امتدادات البروتوكول

يدعم بروتوكول WebSocket الامتدادات التي يتم التفاوض عليها أثناء المصافحة:

// طلب العميل مع الامتداد Sec-WebSocket-Extensions: permessage-deflate; client_max_window_bits // استجابة الخادم تقبل الامتداد Sec-WebSocket-Extensions: permessage-deflate

الامتدادات الشائعة:

  • permessage-deflate: يضغط الرسائل باستخدام خوارزمية DEFLATE (RFC 7692)
  • permessage-deflate; client_no_context_takeover: الضغط بدون سياق بين الرسائل
تحذير الضغط: بينما يقلل الضغط من النطاق الترددي، فإنه يزيد من استخدام وحدة المعالجة المركزية والتأخير. اختبر الأداء مع حمل العمل المحدد الخاص بك قبل تمكينه.

الملخص

يوفر بروتوكول WebSocket اتصالًا فعالًا ثنائي الاتجاه من خلال مصافحة ترقية HTTP، ورؤوس إطار بسيطة، واتصال TCP مستمر. فهم تفاصيل البروتوكول - عملية المصافحة، بنية الإطار، دورة حياة الاتصال، وأكواد الحالة - أمر بالغ الأهمية لبناء تطبيقات قوية في الوقت الفعلي. في الدرس التالي، سنستكشف WebSocket API الأصلي في المتصفح.