4.3الزمن الحقيقي مع مقابس الويب (WebSockets) و Socket.IO
الأساسي في 30 ثانية
- الزمن الحقيقي = الخادم يدفع : لا يكفي HTTP طلب-رد ؛ فيفتح مقبس الويب (WebSocket) اتصالا دائما وثنائي الاتجاه.
- Socket.IO = حدثي : نُصدر (
emit) ونستمع (on) إلى الأحداث، نحو عميل، أو الجميع (broadcast) أو مجموعة (rooms). - منعكس ساليم : يتفوق Node في الزمن الحقيقي (آلاف الاتصالات الدائمة) — وإعادة الاتصال التلقائية والغرف مشمولة.
حالة مصغرة متواصلة — ساليم يضيف دردشة الباعة
يريد باعة ساليم التحادث مباشرة حسب المتجر : رسالة منشورة في الجزائر يجب أن تظهر فورا على شاشة باعة المتجر نفسه، دون إعادة تحميل. الاستطلاع بـ HTTP (إعادة سؤال « هل من جديد ؟ » كل ثانية) بطيء ومبدد : يركب ساليم Socket.IO على خادم Express، ويجعل كل بائع ينضم إلى غرفة (room) متجره، ويبث كل رسالة مستلمة إلى الغرفة. وعندما يسقط الاتصال، يعيد Socket.IO الاتصال وحده. ثالث محطة في الخيط الرابط : يدفع الخادم، وتحيا الشاشات.
تتمة حالة 4.1-4.2 — يجعل ساليم الواجهة المؤمنة حية.
1. لماذا مقابس الويب
نموذج HTTP هو « طلب-رد » : يطلب العميل، ويرد الخادم، ويُغلق الاتصال. وللزمن الحقيقي — الدردشة، والتنبيهات، ولوحة البيانات الحية، واللعب الجماعي، وتتبع التسليم — يجب أن يرسل الخادم بيانات دون أن تُطلب منه، فورا. إعادة السؤال دون توقف (الاستطلاع) تبديد وبطء : والمساومة بين التواتر والكمون مستحيل كسبها.
يحل مقبس الويب (WebSocket) هذا : اتصال دائم وثنائي الاتجاه، يبقى مفتوحا ويترك الطرفين يرسلان رسائل في أي وقت، في الاتجاهين. وهو الآلية الأساسية للزمن الحقيقي على الويب.
2. Socket.IO : الإصدار والاستماع
في Node، المكتبة المرجعية هي Socket.IO : تعمل بطريقة حدثية — نُصدر أحداثا (socket.emit('message', donnees)) ونستمع إليها (socket.on('message', fonction))، لدى الخادم كما لدى العميل. يُصدر الخادم نحو عميل واحد، أو نحو الجميع (io.emit، والبث)، أو نحو مجموعات (الغرف (rooms) : صالون دردشة، أو متجر، أو مباراة).
يضيف Socket.IO ما لا غنى عنه : إعادة الاتصال التلقائية، وحلولا بديلة إذا تعذرت مقابس الويب، والغرف وفضاءات الأسماء، وتوثيق الاتصالات. دردشة ساليم تقوم في أسطر قليلة : رسالة مستلمة ← تُبث إلى الغرفة ← كل الشاشات محدثة، فورا.
3. حالات الاستعمال — وميزة Node
المراسلات، والتنبيهات المباشرة، والبيانات الحية (الأسعار، والمراقبة، والنتائج)، والتعاون (المؤشرات، والتحرير المشترك)، والألعاب الجماعية، والتتبع المباشر : حالما تكسب تطبيقا الاستجابة الفورية، يدخل الزمن الحقيقي — ويكبر هذا المطلب. والخبر السار : يتفوق Node في الزمن الحقيقي، فنموذجه غير الحاجب يدبر بكفاءة آلاف الاتصالات الدائمة المتزامنة. إتقان Socket.IO مهارة فارقة لمطور Node.
استطلاع الفرصة الأخيرة (مشهد لا يُعاد)
العبرة : اتصال مفتوح يدفع خير من ألف سؤال دون جواب.
🔎 مثال ملموس — 🔎 مثال ملموس — دردشة حسب المتجر
دائرة ساليم، ملخصة في أربعة أسطر :
ينضم البائع إلى غرفته : socket.join('boutique-alger')
يرسل البائع : socket.emit('message', texte)
يستقبل الخادم : socket.on('message', ...) ← يعيد البث إلى الغرفة
تستقبل الغرفة : io.to('boutique-alger').emit('message', texte)
القراءة : الإصدار من جهة، والاستماع من جهة أخرى، والبث إلى الغرفة.
الدرس : تنظم الغرف من يستقبل ماذا.
مفردات القسم
- الزمن الحقيقي
- حالات يرسل فيها الخادم بيانات إلى العميل دون أن يطلبها، فورا (دردشة، وتنبيهات، وبيانات حية، وألعاب).
مثال بسيط: تظهر رسالة بائع ساليم فورا لدى زملائه.
ما ليس كذلك: تحميل صفحة عند طلب HTTP كلاسيكي.
رد فعل: حاجة إلى دفع فوري ؟ فكر في مقبس الويب.
- مقبس الويب (WebSocket)
- بروتوكول يقيم اتصالا دائما وثنائي الاتجاه : مفتوح باستمرار، ورسائل في أي وقت في الاتجاهين.
مثال بسيط: الاتصال المفتوح بين متصفح البائع وخادم ساليم.
ما ليس كذلك: طلبات HTTP مكررة بالاستطلاع.
رد فعل: اتصال واحد، ثم رسائل — وليست طلبات.
- Socket.IO
- مكتبة الزمن الحقيقي المرجعية في Node : حدثية (emit/on)، وإعادة اتصال تلقائية، وبدائل، وغرف، وفضاءات أسماء.
مثال بسيط: يضيفها ساليم إلى خادم Express لدردشة المتاجر.
ما ليس كذلك: وحدة مقبس الويب الخام دون إعادة اتصال ولا غرف.
رد فعل: ابدأ بـ Socket.IO، وليس بالخام.
- emit / on
- emit(حدث، بيانات) يرسل ؛ وon(حدث، دالة) يستقبل — من الطرفين، العميل كما الخادم.
مثال بسيط: يُصدر العميل رسالة، ويستمع إليها الخادم ثم يعيد بثها.
ما ليس كذلك: نداء واجهة REST مع رد وحيد.
رد فعل: تسمية الأحداث صراحة وتوثيقها.
- الغرفة (room)
- مجموعة عملاء نبث نحوهم انتقائيا (صالون، أو متجر، أو مباراة).
مثال بسيط: غرفة boutique-alger لساليم تعزل المحادثات حسب المتجر.
ما ليس كذلك: بث إلى كل المتصلين دون تمييز.
رد فعل: الانضمام إلى الغرفة منذ الاتصال الموثق.
في التطبيق — عمليا — إنشاء وظيفة زمن حقيقي
- ركبوا Socket.IO لدى الخادم (على خادم HTTP/Express) وصِلوا عميلا.
- أصدروا واستمعوا إلى الأحداث : العميل socket.emit('message', ...)، والخادم socket.on('message', ...).
- ابثوا إلى كل المتصلين (io.emit(...)) : أنجزوا دردشة بسيطة حيث تُعاد كل رسالة مستلمة إلى الجميع.
- نظموا بالغرف : اجعلوا من ينضم إلى صالون وابثوا فقط في هذا الصالون، كما فعل ساليم حسب المتجر.
نص جاهز للقول — تبرير Socket.IO (30 ثانية)
« معكم ساليم : يحتاج باعتنا المباشر حسب المتجر، واستطلاع HTTP يبدد طلبات ليبقى متأخرا. أقترح Socket.IO : اتصال دائم، وأحداث تُصدر وتُستمع من الطرفين، وبث حسب غرفة المتجر، وإعادة اتصال تلقائية مشمولة. »
يُقال في نقطة تقنية ؛ واعرضوا فرق الاستطلاع مقابل الدفع.
نموذج للنسخ واللصق — خادم Socket.IO بالغرف (كود مختبَر)
const express = require('express');
const http = require('http');
const { Server } = require('socket.io');
const app = express();
const serveur = http.createServer(app);
const io = new Server(serveur);
io.on('connection', (socket) => {
// ينضم كل بائع إلى غرفة متجره
socket.on('rejoindre', (boutique) => {
socket.join(boutique);
socket.to(boutique).emit('info', 'Un vendeur a rejoint ' + boutique);
});
// رسالة مستلمة ← تُعاد إلى غرفة المرسل
socket.on('message', (donnees) => {
// donnees = { boutique: 'boutique-alger', texte: 'Bonjour !' }
if (!donnees.boutique || !donnees.texte) return;
io.to(donnees.boutique).emit('message', {
texte: donnees.texte,
date: new Date().toISOString()
});
});
});
serveur.listen(3000);
// العميل (المتصفح) :
// const socket = io();
// socket.emit('rejoindre', 'boutique-alger');
// socket.emit('message', { boutique: 'boutique-alger', texte: 'Bonjour !' });
// socket.on('message', (m) => console.log(m.texte));
تنبيهات بسيطة
يكفي حدث وحيد نحو الجميع (io.emit) : لا حاجة إلى غرف للوحة تنبيهات شاملة.
دردشة حسب المجموعة
كما يفعل ساليم : غرفة لكل متجر، يُنضم إليها بعد التوثيق — وتعيش كل مجموعة محادثتها.
لوحة بيانات حية
يُصدر الخادم بفاصل منتظم نحو غرفة مشتركين : تتحدث الشاشات وحدها.
اتصالات هشة (هاتف)
دعوا إعادة الاتصال التلقائية تقوم بعملها وأعيدوا إرسال الحالة الراهنة مع كل إعادة اتصال.
✓ ممارسات جيدة
- التفكير أحداثا (emit/on)، وليست طلبات.
- البث نحو المحيط الصحيح (واحد، أو الجميع، أو غرفة).
- التحقق ممن ينضم إلى كل غرفة.
✗ أخطاء شائعة
- الاستطلاع في حلقة بدلا من فتح مقبس ويب.
- البث إلى الجميع ما يخص غرفة.
- قبول اتصالات مجهولة دون ضبط.
النقاط الأساسية
- الزمن الحقيقي = الخادم يدفع فورا (دردشة، وتنبيهات، وحي، وألعاب) — مستحيل في HTTP طلب-رد.
- مقبس الويب : اتصال دائم وثنائي الاتجاه، ورسائل في أي وقت في الاتجاهين.
- Socket.IO : حدثي (emit/on)، وإعادة اتصال تلقائية، وبدائل، وغرف. عميل واحد، أو الجميع (البث)، أو غرفة.
- يتفوق Node في الزمن الحقيقي (آلاف الاتصالات الدائمة). مهارة فارقة.
تحدي 48 ساعة — طبّق غدا
أنجزوا دردشة مصغرة بغرفتين : الانضمام، والإرسال، والاستلام — ثم افصلوا الشبكة وراقبوا إعادة الاتصال.
- أستطيع شرح مقبس الويب وemit/on والغرف.
- أعرف لماذا لا يصلح الاستطلاع.
- لدي دردشة زمن حقيقي بالغرف تشتغل.
أسئلة شائعة
لماذا مقابس الويب بدلا من طلبات HTTP مكررة (الاستطلاع) ؟
لأن HTTP يبادر به العميل : لا يستطيع الخادم الدفع تلقائيا. يبدد الاستطلاع (إعادة سؤال « هل من جديد ؟ ») (طلبات فارغة، وعرض نطاق، وبطارية) ويبقى متأخرا (حتى الفاصل). يحسن الاستطلاع الطويل قليلا لكنه يبقى تحايلا على HTTP. يقيم مقبس الويب اتصالا دائما ثنائي الاتجاه : يدفع الخادم فورا، دون حمل زائد — الحل الصحيح، الأنيق والمقتصد.
أي أنواع التطبيقات يتيحها الزمن الحقيقي — وهل تعلمه مربح ؟
الدردشات والمراسلات، والتنبيهات المباشرة، ولوحات البيانات الحية (أسعار، ومراقبة، ونتائج)، والتعاون (تحرير مشترك، ومؤشرات)، والألعاب الجماعية، والتتبع المباشر (تسليمات)، والمزادات والتصويتات الحية. مطلب التفاعلية يكبر في كل مكان — ويتفوق Node، بنموذجه غير الحاجب المصمم لآلاف الاتصالات الدائمة، فيه. ولمطور Node، ميزة فارقة مطلوبة جدا.
ماذا يتيح مقبس الويب مقابل HTTP الكلاسيكي ؟