المشكلة: وقت استجابة منخفض لعمليات الاتصال بين العميل والخادم والخادم والعميل
تم بناء شبكة الويب بشكل كبير استنادًا إلى ما يُعرف بنموذج الطلب/الاستجابة HTTP. يُحمِّل العميل صفحة ويب، ولا يحدث أيّ شيء إلى أن ينقر المستخدم على الصفحة التالية. في عام 2005 تقريبًا، بدأت تقنية AJAX في جعل الويب أكثر ديناميكية. ومع ذلك، كان العميل يدير جميع عمليات تبادل البيانات عبر بروتوكول HTTP، ما كان يتطلّب تفاعل المستخدم أو إجراء عمليات استطلاع دورية لتحميل بيانات جديدة من الخادم.
يشير ذلك المصطلح إلى التكنولوجيات التي تمكّن الخادم من إرسال البيانات إلى العميل في اللحظة التي يُدرك فيها توفُّر بيانات جديدة. وتُعرف هذه الرسائل باسم "Push" أو "Comet". إنّ إحدى الطرق الأكثر شيوعًا لخداع المستخدمين وإيهامهم بأنّ الاتصال قد بدأ من الخادم تُعرف باسم "الاستطلاع الطويل". باستخدام ميزة "الاستطلاع الطويل"، يفتح العميل اتصالاً عبر بروتوكول HTTP مع الخادم ويبقيه مفتوحًا إلى أن يتم إرسال الاستجابة. وعندما يكون لدى الخادم بيانات جديدة، فإنه يرسل الاستجابة (تتضمن أساليب أخرى Flash وطلبات XHR متعددة الأجزاء وتُعرف باسم htmlfiles). تعمل تقنية "الاستطلاع الطويل" والأساليب الأخرى بشكل جيد جدًا. ويمكنك استخدامها يوميًا في تطبيقات مثل Chat في Gmail.
ومع ذلك، تشترك جميع الحلول البديلة هذه في مشكلة واحدة: فهي تتحمل النفقات العامة لبروتوكول HTTP، ما يجعلها غير مناسبة للتطبيقات التي تتطلب وقت استجابة منخفضًا. تشمل هذه الألعاب ألعاب الرماية من منظور البطل المتعدّدة اللاعبين في المتصفّح أو أي لعبة أخرى على الإنترنت تتضمّن مكوّنًا في الوقت الفعلي.
تقديم WebSocket: توفير مآخذ على الويب
تحدد مواصفات WebSocket واجهة برمجة تطبيقات تُنشئ اتصالات "socket" بين متصفح ويب وخادم. بعبارة أخرى، هناك اتصال دائم بين العميل والخادم ويمكن لكلا الطرفَين بدء إرسال البيانات في أي وقت.
البدء
يمكنك فتح اتصال WebSocket ببساطة عن طريق استدعاء عنصر الإنشاء WebSocket:
var connection = new WebSocket('ws://html5rocks.websocket.org/echo', ['soap', 'xmpp']);
لاحظ ws:
. هذا هو مخطط عنوان URL الجديد لاتصالات WebSocket. هناك أيضًا wss:
لاتصال WebSocket الآمن بالطريقة نفسها التي يتم بها استخدام https:
لاتصالات HTTP الآمنة.
من خلال إرفاق بعض معالجات الأحداث بالاتصال مباشرةً، يمكنك معرفة وقت فتح الاتصال أو تلقّي الرسائل الواردة أو حدوث خطأ.
تقبل الوسيطة الثانية البروتوكولات الفرعية الاختيارية. يمكن أن تكون سلسلة أو مصفوفة من السلاسل. ينبغي أن تمثل كل سلسلة اسم بروتوكول فرعي ويقبل الخادم واحدًا فقط من البروتوكولات الفرعية التي تم تمريرها في المصفوفة. يمكن تحديد البروتوكول الفرعي المقبول من خلال الوصول إلى سمة protocol
لكائن WebSocket.
يجب أن تكون أسماء البروتوكولات الفرعية واحدة من أسماء البروتوكولات الفرعية المسجّلة في سجلّ IANA. لا يتوفّر حاليًا سوى اسم بروتوكول فرعي واحد (soap) مسجَّل اعتبارًا من شباط (فبراير) 2012.
// When the connection is open, send some data to the server
connection.onopen = function () {
connection.send('Ping'); // Send the message 'Ping' to the server
};
// Log errors
connection.onerror = function (error) {
console.log('WebSocket Error ' + error);
};
// Log messages from the server
connection.onmessage = function (e) {
console.log('Server: ' + e.data);
};
التواصل مع الخادم
بعد أن نتصل بالخادم (عند بدء حدث open
)، يمكننا بدء إرسال البيانات إلى الخادم باستخدام طريقة send('your message')
في عنصر الاتصال. كان هذا البروتوكول يتيح إرسال سلاسل فقط، ولكن في أحدث المواصفات، يمكنه الآن إرسال رسائل ثنائية أيضًا. لإرسال البيانات الثنائية، يمكنك استخدام كائن Blob
أو ArrayBuffer
.
// Sending String
connection.send('your message');
// Sending canvas ImageData as ArrayBuffer
var img = canvas_context.getImageData(0, 0, 400, 320);
var binary = new Uint8Array(img.data.length);
for (var i = 0; i < img.data.length; i++) {
binary[i] = img.data[i];
}
connection.send(binary.buffer);
// Sending file as Blob
var file = document.querySelector('input[type="file"]').files[0];
connection.send(file);
وبالمثل، يمكن للخادم إرسال رسائل إلينا في أي وقت. وعندما يحدث ذلك، يتم تنشيط معاودة الاتصال onmessage
. يتلقّى الإجراء المُعاد الاتصال به عنصر حدث ويمكن الوصول إلى الرسالة الفعلية من خلال السمة data
.
يمكن أن يتلقّى بروتوكول WebSocket أيضًا رسائل ثنائية في أحدث المواصفات. ويمكن تلقّي الإطارات الثنائية بتنسيق Blob
أو ArrayBuffer
. لتحديد تنسيق الملف الثنائي المستلَم، اضبط سمة binaryType لكائن WebSocket على "blob" أو "arraybuffer". التنسيق التلقائي هو "blob". (ليس عليك محاذاة مَعلمة للتحقّق من الأوليّة عند الإرسال.)
// Setting binaryType to accept received binary as either 'blob' or 'arraybuffer'
connection.binaryType = 'arraybuffer';
connection.onmessage = function(e) {
console.log(e.data.byteLength); // ArrayBuffer object if binary
};
من الميزات الأخرى التي تمت إضافتها مؤخرًا إلى WebSocket هي الإضافات. باستخدام الإضافات، سيكون من الممكن إرسال إطارات مضغوطة ومتعدّدة القنوات وما إلى ذلك. يمكنك العثور على الإضافات المقبولة من الخادم من خلال فحص سمة الإضافات لواجهة WebSocket بعد الحدث المفتوح. لم يتم نشر مواصفات رسمية للإضافة حتى الآن اعتبارًا من شباط (فبراير) 2012.
// Determining accepted extensions
console.log(connection.extensions);
التواصل من مصادر متعددة
بما أنّ WebSocket هو بروتوكول حديث، تم تضمين ميزة التواصل بين مصادر مختلفة فيه. على الرغم من ضرورة التأكد فقط من التواصل مع العملاء والخوادم التي تثق بها، يتيح WebSocket الاتصال بين الأطراف على أي نطاق. يقرّر الخادم ما إذا كان سيتيح خدمته لجميع العملاء أو فقط لأولئك الذين يقيمون في مجموعة من النطاقات المحدّدة بوضوح.
الخوادم الوكيلة
تأتي كل تكنولوجيا جديدة مع مجموعة جديدة من المشكلات. في ما يتعلّق بـ WebSocket، فإنّه يتوافق مع الخوادم الوكيلة التي تتوسّط اتصالات HTTP في معظم شبكات الشركات. يستخدم بروتوكول WebSocket نظام ترقية HTTP (الذي يُستخدم عادةً لبروتوكول HTTP/SSL) من أجل "ترقية" اتصال HTTP إلى اتصال WebSocket. لا تتوافق بعض خوادم الوكيل مع هذا الإجراء، ما يؤدي إلى قطع الاتصال. وبالتالي، حتى إذا كان أحد العملاء يستخدم بروتوكول WebSocket، قد لا يكون من الممكن إنشاء اتصال. وهذا يجعل القسم التالي أكثر أهمية.
استخدام WebSockets اليوم
لا تزال تقنية WebSocket جديدة ولم يتم تنفيذها بالكامل في جميع المتصفّحات. ومع ذلك، يمكنك استخدام WebSocket اليوم مع المكتبات التي تستخدم أحد الحلول الاحتياطية المذكورة أعلاه في حال عدم توفّر WebSocket. من المكتبات التي أصبحت رائجة جدًا في هذا المجال هي socket.io التي تأتي مع تنفيذ بروتوكول العميل والخادم وتشمل عمليات الاستبدال (لا تتوافق socket.io مع المراسلة الثنائية حتى الآن اعتبارًا من شباط (فبراير) 2012). هناك أيضًا حلول تجارية مثل PusherApp التي يمكن دمجها بسهولة في أي بيئة ويب من خلال توفير واجهة برمجة تطبيقات HTTP لإرسال رسائل WebSocket إلى العملاء. بسبب طلب HTTP الإضافي، سيكون هناك دائمًا عبء إضافي مقارنةً بـ WebSocket.
جهة الخادم
يؤدي استخدام WebSocket إلى إنشاء نمط استخدام جديد تمامًا للتطبيقات من جهة الخادم. على الرغم من تصميم حزم الخادم التقليدية مثل LAMP حول دورة طلب/استجابة HTTP، فإنها لا تتعامل غالبًا مع عدد كبير من اتصالات WebSocket المفتوحة. إنّ إبقاء عدد كبير من الاتصالات مفتوحة في الوقت نفسه يتطلّب بنية معمارية تتلقّى عددًا كبيرًا من عمليات الربط المتزامنة بتكلفة أداء منخفضة. وعادةً ما يتم تصميم هذه التصاميم حول خيوط المعالجة أو ما يُعرف باسم "إدخال/إخراج غير حظر".
عمليات التنفيذ من جهة الخادم
- Node.js
- Java
- ياقوت أحمر
- Python
- وحدة قياس زمن الانتظار (Erlang)
- لغة C++
- .NET
إصدارات البروتوكول
أصبح البروتوكول السلكي (المصافحة ونقل البيانات بين العميل والخادم) في WebSocket الآن RFC6455. إنّ أحدث إصدارَي Chrome وChrome لأجهزة Android متوافقان تمامًا مع RFC6455، بما في ذلك المراسلة الثنائية. وسيتوافق متصفح فايرفوكس مع الإصدار 11 من Internet Explorer في الإصدار 10. سيظل بإمكانك استخدام إصدارات البروتوكول القديمة، ولكن لا يُنصح بذلك لأنّها معروفة بأنّها معرّضة للاختراق. إذا كانت لديك عمليات تنفيذ خادم لإصدارات قديمة من بروتوكول WebSocket، ننصحك بترقيتها إلى أحدث إصدار.
حالات الاستخدام
استخدِم WebSocket متى احتجت إلى وقت استجابة سريع جدًا واتصال في الوقت الفعلي تقريبًا بين العميل والخادم. يُرجى العِلم أنّ هذا قد يتطلّب إعادة التفكير في كيفية إنشاء تطبيقاتك من جهة الخادم مع التركيز بشكل جديد على تقنيات مثل قوائم انتظار الأحداث. في ما يلي بعض أمثلة حالات الاستخدام:
- الألعاب المتعدّدة اللاعبين على الإنترنت
- تطبيقات المحادثات
- شريط الأخبار الرياضية المباشر
- أحداث البث على وسائل التواصل الاجتماعي التي يتم تعديلها في الوقت الفعلي
إصدارات تجريبية
- Plink
- Paint With Me
- Pixelatr
- خط متقطّع
- لعبة كلمات متقاطعة متعددة اللاعبين على الإنترنت
- خادم "إرسال طلب فحص الاتصال" (المستخدَم في الأمثلة أعلاه)
- نموذج HTML5demos