إنشاء خدمات الخلفية اللازمة لتطبيق WebRTC

ما هي الإشارات؟

الإشارة هي عملية تنسيق التواصل. لكي يتمكّن تطبيق WebRTC من إعداد مكالمة، يجب أن يتبادل العملاء المعلومات التالية:

  • رسائل التحكّم في الجلسة المستخدَمة لفتح الاتصال أو إغلاقه
  • رسائل الخطأ
  • البيانات الوصفية للوسائط، مثل برامج الترميز وإعدادات برامج الترميز ومعدل نقل البيانات وأنواع الوسائط
  • البيانات الأساسية المستخدَمة لإنشاء اتصالات آمنة
  • بيانات الشبكة، مثل عنوان IP للمضيف والمنفذ كما يظهران للعالم الخارجي

تتطلّب عملية الإشارة هذه طريقة لتبادل الرسائل بين العملاء. لا توفّر واجهات برمجة التطبيقات WebRTC هذه الآلية. عليك إنشاء هذا التطبيق بنفسك. في وقت لاحق من هذه المقالة، ستتعرّف على طرق إنشاء خدمة إشارات. أولاً، عليك معرفة بعض المعلومات الأساسية.

لماذا لا يحدّد WebRTC عملية الإرسال؟

ولتجنُّب التكرار وتحقيق الحد الأقصى من التوافق مع التقنيات المعمول بها، لا تحدّد معايير WebRTC طرق وبروتوكولات الإشارات. يتم توضيح هذا النهج من خلال بروتوكول إنشاء جلسة JavaScript (JSEP):

تتجنّب بنية JSEP أيضًا الحاجة إلى أن يحفظ المتصفّح الحالة، أي أن يعمل كآلة حالة إرسال إشارات. سيشكّل ذلك مشكلة إذا تم، على سبيل المثال، فقدان بيانات الإشارات في كل مرة يتم فيها إعادة تحميل الصفحة. بدلاً من ذلك، يمكن حفظ حالة الإشارة على خادم.

مخطّط بنية JSEP
بنية JSEP

يتطلّب JSEP تبادلاً بين الأجهزة النظيرة للعرض والردّ، أي بيانات وصفية للوسائط المذكورة أعلاه. يتم إرسال العروض والردود بتنسيق بروتوكول وصف الجلسة (SDP)، ويكون شكلها على النحو التالي:

v=0
o=- 7614219274584779017 2 IN IP4 127.0.0.1
s=-
t=0 0
a=group:BUNDLE audio video
a=msid-semantic: WMS
m=audio 1 RTP/SAVPF 111 103 104 0 8 107 106 105 13 126
c=IN IP4 0.0.0.0
a=rtcp:1 IN IP4 0.0.0.0
a=ice-ufrag:W2TGCZw2NZHuwlnf
a=ice-pwd:xdQEccP40E+P0L5qTyzDgfmW
a=extmap:1 urn:ietf:params:rtp-hdrext:ssrc-audio-level
a=mid:audio
a=rtcp-mux
a=crypto:1 AES_CM_128_HMAC_SHA1_80 inline:9c1AHz27dZ9xPI91YNfSlI67/EMkjHHIHORiClQe
a=rtpmap:111 opus/48000/2

هل تريد معرفة ما تعنيه كل هذه المصطلحات المعقّدة المتعلّقة ببروتوكول وصف الجلسة؟ اطّلِع على أمثلة مجموعة مهندسي شبكة الإنترنت (IETF).

يُرجى العِلم أنّ WebRTC مصمَّمة بحيث يمكن تعديل العرض أو الردّ قبل ضبطه كوصف محلي أو بعيد من خلال تعديل القيم في نص SDP. على سبيل المثال، يمكن استخدام الدالة preferAudioCodec() في appr.tc لضبط الترميز ومعدّل نقل البيانات التلقائيين. من الصعب إلى حدّ ما التعامل مع وصف الجلسة (SDP) باستخدام JavaScript، وهناك نقاش حول ما إذا كان يجب أن تستخدم الإصدارات المستقبلية من WebRTC تنسيق JSON بدلاً من ذلك، ولكن هناك بعض المزايا لاستخدام وصف الجلسة (SDP).

RTCPeerConnection واجهة برمجة التطبيقات والإشارات: العرض والإجابة والمرشّح

RTCPeerConnection هي واجهة برمجة التطبيقات التي تستخدمها تطبيقات WebRTC لإنشاء اتصال بين الأجهزة المتصلة بالشبكة وتبادل الصوت والفيديو.

لبدء هذه العملية، يتضمّن RTCPeerConnection مهمتَين:

  • تأكَّد من توفّر شروط الوسائط المحلية، مثل إمكانات الدقة وبرامج الترميز. هذه هي البيانات الوصفية المستخدَمة في آلية العرض والرد.
  • الحصول على عناوين شبكة محتملة لمضيف التطبيق، والمعروفة باسم العناوين المرشّحة

بعد التأكّد من توفّر هذه البيانات المحلية، يجب تبادلها مع الجهاز البعيد من خلال آلية إرسال إشارات.

لنفترض أنّ أليس تحاول الاتصال بإيف. إليك آلية العرض/الرد الكاملة بكل تفاصيلها:

  1. تنشئ "أليس" كائن RTCPeerConnection.
  2. تنشئ "أليس" عرضًا (وصف جلسة SDP) باستخدام الطريقة RTCPeerConnection createOffer().
  3. تتصل "أليس" برقم setLocalDescription() لتقديم عرضها.
  4. تحوّل "أليس" العرض إلى سلسلة وتستخدم آلية إرسال إشارات لإرساله إلى "إيف".
  5. تتصل "إيف" setRemoteDescription() بعرض "أليس"، لكي يعرف RTCPeerConnection إعدادات "أليس".
  6. تتصل "إيف" بـ createAnswer() ويتم تمرير وصف جلسة محلية إلى دالة معاودة الاتصال الناجحة، وهو رد "إيف".
  7. تضبط "إيف" إجابتها كالوصف المحلي من خلال استدعاء setLocalDescription().
  8. تستخدم إيف بعد ذلك آلية الإشارة لإرسال إجابتها المحوَّلة إلى سلسلة إلى أليس.
  9. تضبط "أليس" إجابة "إيف" كوصف للجلسة البعيدة باستخدام setRemoteDescription().

على "أليس" و"إيف" أيضًا تبادل معلومات الشبكة. يشير المصطلح "العثور على مرشّحين" إلى عملية العثور على منافذ وواجهات شبكة باستخدام إطار عمل ICE.

  1. تنشئ "أليس" عنصر RTCPeerConnection باستخدام معالج onicecandidate.
  2. يتم استدعاء المعالج عندما تصبح شبكات مرشحة متاحة.
  3. في المعالج، ترسل "أليس" بيانات المرشح المحوَّلة إلى سلسلة إلى "إيف" من خلال قناة الإشارات.
  4. عندما تتلقّى إيف رسالة مرشّحة من أليس، تستدعي addIceCandidate() لإضافة المرشّح إلى وصف الند الخارجي.

يتوافق JSEP مع نقل بيانات مرشّح ICE، ما يتيح للمتصل تقديم المرشّحين بشكل تدريجي إلى المتلقّي بعد العرض الأولي، كما يتيح للمتلقّي بدء اتخاذ إجراء بشأن المكالمة وإعداد اتصال بدون انتظار وصول جميع المرشّحين.

كتابة رمز WebRTC للإشارة

مقتطف الرمز التالي هو مثال على رمز W3C يلخّص عملية إرسال الإشارات الكاملة. يفترض الرمز البرمجي توفّر بعض آليات الإشارة، SignalingChannel. سيتم تناول موضوع الإشارات بمزيد من التفصيل لاحقًا.

// handles JSON.stringify/parse
const signaling = new SignalingChannel();
const constraints = {audio: true, video: true};
const configuration = {iceServers: [{urls: 'stun:stun.example.org'}]};
const pc = new RTCPeerConnection(configuration);

// Send any ice candidates to the other peer.
pc.onicecandidate = ({candidate}) => signaling.send({candidate});

// Let the "negotiationneeded" event trigger offer generation.
pc.onnegotiationneeded = async () => {
  try {
    await pc.setLocalDescription(await pc.createOffer());
    // send the offer to the other peer
    signaling.send({desc: pc.localDescription});
  } catch (err) {
    console.error(err);
  }
};

// After remote track media arrives, show it in remote video element.
pc.ontrack = (event) => {
  // Don't set srcObject again if it is already set.
  if (remoteView.srcObject) return;
  remoteView.srcObject = event.streams[0];
};

// Call start() to initiate.
async function start() {
  try {
    // Get local stream, show it in self-view, and add it to be sent.
    const stream =
      await navigator.mediaDevices.getUserMedia(constraints);
    stream.getTracks().forEach((track) =>
      pc.addTrack(track, stream));
    selfView.srcObject = stream;
  } catch (err) {
    console.error(err);
  }
}

signaling.onmessage = async ({desc, candidate}) => {
  try {
    if (desc) {
      // If you get an offer, you need to reply with an answer.
      if (desc.type === 'offer') {
        await pc.setRemoteDescription(desc);
        const stream =
          await navigator.mediaDevices.getUserMedia(constraints);
        stream.getTracks().forEach((track) =>
          pc.addTrack(track, stream));
        await pc.setLocalDescription(await pc.createAnswer());
        signaling.send({desc: pc.localDescription});
      } else if (desc.type === 'answer') {
        await pc.setRemoteDescription(desc);
      } else {
        console.log('Unsupported SDP type.');
      }
    } else if (candidate) {
      await pc.addIceCandidate(candidate);
    }
  } catch (err) {
    console.error(err);
  }
};

للاطّلاع على عمليات العرض/الرد وتبادل المرشحين أثناء التنفيذ، يمكنك الانتقال إلى simpl.info RTCPeerConnection والاطّلاع على سجلّ وحدة التحكّم للحصول على مثال على محادثة فيديو من صفحة واحدة. إذا أردت الحصول على المزيد، يمكنك تنزيل تفريغ كامل لإشارات WebRTC وإحصاءاتها من صفحة about://webrtc-internals في Google Chrome أو صفحة opera://webrtc-internals في Opera.

Peer discovery

هذه طريقة فصيحة للسؤال عن "كيف يمكنني العثور على شخص أتحدث معه؟"

بالنسبة إلى المكالمات الهاتفية، لديك أرقام هواتف وأدلة. بالنسبة إلى محادثات الفيديو والمراسلة على الإنترنت، تحتاج إلى أنظمة لإدارة الهوية وحالة التوفّر، ووسيلة تتيح للمستخدمين بدء الجلسات. تحتاج تطبيقات WebRTC إلى طريقة تتيح للعملاء إرسال إشارات إلى بعضهم البعض لإعلامهم برغبتهم في بدء مكالمة أو الانضمام إليها.

لا تحدّد WebRTC آليات العثور على الأجهزة المتصلة بالشبكة المحلية، ولن نتناول الخيارات هنا. يمكن أن تكون العملية بسيطة مثل إرسال عنوان URL عبر البريد الإلكتروني أو الرسائل. بالنسبة إلى تطبيقات محادثات الفيديو، مثل Talky وtawk.to وBrowser Meeting، يمكنك دعوة الأشخاص إلى مكالمة من خلال مشاركة رابط مخصّص. أنشأ المطوّر كريس بول تجربة serverless-webrtc مثيرة للاهتمام تتيح للمشاركين في مكالمة WebRTC تبادل البيانات الوصفية باستخدام أي خدمة مراسلة يفضّلونها، مثل المراسلة الفورية أو البريد الإلكتروني أو الحمام الزاجل.

كيف يمكن إنشاء خدمة إشارات؟

نكرّر أنّ بروتوكولات وآليات الإشارة غير محدّدة بمعايير WebRTC. بغض النظر عن اختيارك، تحتاج إلى خادم وسيط لتبادل رسائل الإشارة وبيانات التطبيق بين العملاء. للأسف، لا يمكن لتطبيق الويب أن يطلب ببساطة من الإنترنت "أريد التواصل مع صديقي".

لحسن الحظ، رسائل الإشارة صغيرة ويتم تبادلها في الغالب عند بدء المكالمة. في اختبار باستخدام appr.tc لجلسة محادثة فيديو، تعاملت خدمة الإشارات مع ما مجموعه 30 إلى 45 رسالة تقريبًا، وكان إجمالي حجم جميع الرسائل حوالي 10 كيلوبايت.

بالإضافة إلى أنّ خدمات إرسال الإشارات في WebRTC لا تتطلّب نطاقًا تردديًا كبيرًا، فهي لا تستهلك الكثير من المعالجة أو الذاكرة لأنّها تحتاج فقط إلى نقل الرسائل والاحتفاظ بكمية صغيرة من بيانات حالة الجلسة، مثل العملاء المتصلين.

إرسال الرسائل من الخادم إلى العميل

يجب أن تكون خدمة الرسائل اللازمة لإرسال الإشارات ثنائية الاتجاه: من العميل إلى الخادم ومن الخادم إلى العميل. يتعارض الاتصال الثنائي الاتجاه مع نموذج طلب/ردّ العميل/الخادم في HTTP، ولكن تم تطوير العديد من الحلول البديلة، مثل الاستقصاء الطويل على مدار سنوات عديدة من أجل إرسال البيانات من خدمة تعمل على خادم ويب إلى تطبيق ويب يعمل في متصفح.

في الآونة الأخيرة، تم تنفيذ واجهة برمجة التطبيقات EventSource على نطاق واسع. يتيح ذلك إرسال الأحداث من الخادم، أي البيانات المُرسَلة من خادم ويب إلى برنامج متصفّح من خلال HTTP. تم تصميم EventSource للمراسلة في اتجاه واحد، ولكن يمكن استخدامه مع XHR لإنشاء خدمة لتبادل رسائل الإشارة. تمرّر خدمة الإشارات رسالة من المتصل، يتم تسليمها من خلال طلب XHR، عن طريق إرسالها عبر EventSource إلى المتلقّي.

WebSocket هو حلّ أكثر طبيعية، وهو مصمّم للتواصل الكامل بين العميل والخادم في الاتجاهين، أي الرسائل التي يمكن أن تنتقل في كلا الاتجاهين في الوقت نفسه. إحدى مزايا خدمة الإشارات التي تم إنشاؤها باستخدام WebSocket أو أحداث من جهة الخادم (EventSource) هي أنّه يمكن تنفيذ الخلفية لواجهات برمجة التطبيقات هذه على مجموعة متنوعة من أُطر عمل الويب الشائعة في معظم حِزم استضافة الويب للغات مثل PHP وPython وRuby.

تتيح جميع المتصفّحات الحديثة بروتوكول WebSocket باستثناء Opera Mini، والأهم من ذلك أنّ جميع المتصفّحات التي تتيح WebRTC تتيح أيضًا WebSocket على كل من أجهزة الكمبيوتر والأجهزة الجوّالة. يجب استخدام TLS لجميع الاتصالات لضمان عدم اعتراض الرسائل بدون تشفير، وكذلك للحدّ من المشاكل المتعلقة باجتياز الخادم الوكيل. (لمزيد من المعلومات حول WebSocket وعملية اجتياز الخادم الوكيل، يمكنك الاطّلاع على فصل WebRTC في كتاب High Performance Browser Networking من تأليف "إيليا غريغوريك").

من الممكن أيضًا التعامل مع الإشارات من خلال جعل برامج WebRTC تستقصي خادم الرسائل بشكل متكرر من خلال Ajax، ولكن يؤدي ذلك إلى العديد من طلبات الشبكة الزائدة، وهو أمر يسبّب مشاكل خاصة للأجهزة الجوّالة. حتى بعد إنشاء جلسة، يجب أن يطلب النظراء رسائل الإشارة في حال حدوث تغييرات أو إنهاء الجلسة من قِبل نظراء آخرين. يستخدم مثال تطبيق WebRTC Book هذا الخيار مع بعض التحسينات على معدّل تكرار الاستطلاع.

إرسال الإشارات على نطاق واسع

على الرغم من أنّ خدمة الإشارات تستهلك نطاقًا تردديًا ووحدة معالجة مركزية قليلاً نسبيًا لكل عميل، قد تحتاج خوادم الإشارات لتطبيق شائع إلى معالجة الكثير من الرسائل من مواقع مختلفة بمستويات تزامن عالية. تحتاج تطبيقات WebRTC التي تتلقّى عددًا كبيرًا من الزيارات إلى خوادم إرسال إشارات قادرة على التعامل مع أحمال كبيرة. لا نتناول التفاصيل هنا، ولكن تتوفّر عدة خيارات لإرسال الرسائل بكميات كبيرة وبأداء عالٍ، بما في ذلك ما يلي:

  • بروتوكول المراسلة والحضور القابل للتوسيع (XMPP)، المعروف في الأصل باسم Jabber، وهو بروتوكول تم تطويره للمراسلة الفورية ويمكن استخدامه للإشارة (تشمل عمليات تنفيذ الخادم ejabberd وOpenfire). تستخدم برامج JavaScript، مثل Strophe.js، BOSH لمحاكاة البث الثنائي الاتجاه، ولكن لأسباب مختلفة، قد لا تكون BOSH فعّالة مثل WebSocket، وللأسباب نفسها، قد لا تتوسّع بشكل جيد.) (Jingle هي إضافة إلى XMPP تتيح إجراء مكالمات صوتية ومكالمات فيديو. يستخدم مشروع WebRTC مكوّنات الشبكة والنقل من مكتبة libjingle، وهي عملية تنفيذ بلغة C++ لبروتوكول Jingle.

  • مكتبات مفتوحة المصدر، مثل ZeroMQ (كما تستخدمها TokBox في خدمة Rumour) وOpenMQ (تطبّق NullMQ مفاهيم ZeroMQ على منصات الويب باستخدام بروتوكول STOMP عبر WebSocket).

  • منصات المراسلة التجارية المستندة إلى السحابة الإلكترونية والتي تستخدم WebSocket (مع إمكانية الرجوع إلى الاستقصاء الطويل)، مثل Pusher وKaazing وPubNub (تتضمّن PubNub أيضًا واجهة برمجة تطبيقات لـ WebRTC)

  • منصات WebRTC التجارية، مثل vLine

(يقدّم دليل تكنولوجيات الويب في الوقت الفعلي الذي أعدّه المطوّر "فيل ليغتر" قائمة شاملة بخدمات المراسلة والمكتبات).

إنشاء خدمة إشارات باستخدام Socket.io على Node

في ما يلي رمز لتطبيق ويب بسيط يستخدم خدمة إرسال إشارات تم إنشاؤها باستخدام Socket.io على Node. يسهّل تصميم Socket.io إنشاء خدمة لتبادل الرسائل، كما أنّها مناسبة بشكل خاص لإشارات WebRTC بسبب مفهوم الغرف المضمّن فيها. هذا المثال غير مصمّم ليتم توسيعه كخدمة إشارات ذات مستوى إنتاج، ولكنّه بسيط الفهم لعدد صغير نسبيًا من المستخدمين.

تستخدم Socket.io بروتوكول WebSocket مع بدائل: استقصاء AJAX الطويل، وبث AJAX متعدد الأجزاء، وإطار Forever Iframe، واستقصاء JSONP. تم نقلها إلى العديد من الأنظمة الخلفية، ولكن ربما تشتهر بإصدار Node المستخدم في هذا المثال.

لا يتضمّن هذا المثال WebRTC. تم تصميم هذا التطبيق فقط لتوضيح كيفية إنشاء إشارات في تطبيق ويب. اطّلِع على سجلّ وحدة التحكّم لمعرفة ما يحدث عندما ينضم العملاء إلى غرفة ويتبادلون الرسائل. يقدّم درس الترميز التطبيقي WebRTC تعليمات مفصّلة حول كيفية دمج هذه الميزة في تطبيق كامل لمحادثة الفيديو باستخدام WebRTC.

في ما يلي معرّف العميل index.html:

<!DOCTYPE html>
<html>
  <head>
    <title>WebRTC client</title>
  </head>
  <body>
    <script src='/https/web.dev/socket.io/socket.io.js'></script>
    <script src='js/main.js'></script>
  </body>
</html>

إليك ملف JavaScript main.js المُشار إليه في العميل:

const isInitiator;

room = prompt('Enter room name:');

const socket = io.connect();

if (room !== '') {
  console.log('Joining room ' + room);
  socket.emit('create or join', room);
}

socket.on('full', (room) => {
  console.log('Room ' + room + ' is full');
});

socket.on('empty', (room) => {
  isInitiator = true;
  console.log('Room ' + room + ' is empty');
});

socket.on('join', (room) => {
  console.log('Making request to join room ' + room);
  console.log('You are the initiator!');
});

socket.on('log', (array) => {
  console.log.apply(console, array);
});

في ما يلي تطبيق الخادم الكامل:

const static = require('node-static');
const http = require('http');
const file = new(static.Server)();
const app = http.createServer(function (req, res) {
  file.serve(req, res);
}).listen(2013);

const io = require('socket.io').listen(app);

io.sockets.on('connection', (socket) => {

  // Convenience function to log server messages to the client
  function log(){
    const array = ['>>> Message from server: '];
    for (const i = 0; i < arguments.length; i++) {
      array.push(arguments[i]);
    }
      socket.emit('log', array);
  }

  socket.on('message', (message) => {
    log('Got message:', message);
    // For a real app, would be room only (not broadcast)
    socket.broadcast.emit('message', message);
  });

  socket.on('create or join', (room) => {
    const numClients = io.sockets.clients(room).length;

    log('Room ' + room + ' has ' + numClients + ' client(s)');
    log('Request to create or join room ' + room);

    if (numClients === 0){
      socket.join(room);
      socket.emit('created', room);
    } else if (numClients === 1) {
      io.sockets.in(room).emit('join', room);
      socket.join(room);
      socket.emit('joined', room);
    } else { // max two clients
      socket.emit('full', room);
    }
    socket.emit('emit(): client ' + socket.id +
      ' joined room ' + room);
    socket.broadcast.emit('broadcast(): client ' + socket.id +
      ' joined room ' + room);

  });

});

(لا تحتاج إلى التعرّف على node-static لتنفيذ هذا الإجراء. (يتم استخدامه في هذا المثال فقط).

لتشغيل هذا التطبيق على المضيف المحلي، يجب تثبيت Node وSocket.IO وnode-static. يمكن تنزيل Node من Node.js (عملية التثبيت بسيطة وسريعة). لتثبيت Socket.IO وnode-static، شغِّل Node Package Manager من نافذة طرفية في دليل تطبيقك:

npm install socket.io
npm install node-static

لبدء الخادم، شغِّل الأمر التالي من وحدة طرفية في دليل تطبيقك:

node server.js

افتح localhost:2013 من المتصفّح. افتح علامة تبويب أو نافذة جديدة في أي متصفّح وافتح localhost:2013 مرة أخرى. للاطّلاع على ما يحدث، تحقَّق من وحدة التحكّم. في Chrome وOpera، يمكنك الوصول إلى وحدة التحكّم من خلال "أدوات مطوّري البرامج في Google Chrome" باستخدام Ctrl+Shift+J (أو Command+Option+J على جهاز Mac).

بغض النظر عن الطريقة التي تختارها لإرسال الإشارات، يجب أن يوفّر تطبيق الخلفية وتطبيق العميل خدمات مشابهة لهذا المثال على الأقل.

المشاكل المحتملة في إرسال الإشارات

  • لن يبدأ RTCPeerConnection في جمع المرشحين إلا بعد استدعاء setLocalDescription(). هذا الإجراء إلزامي في مسودة JSEP IETF.
  • استفِد من ميزة Trickle ICE. اتّصِل على الرقم addIceCandidate() فور وصول المرشحين.

خوادم الإشارات الجاهزة

إذا كنت لا تريد إنشاء خادم الإشارات الخاص بك، تتوفّر عدة خوادم إشارات WebRTC تستخدم Socket.IO مثل المثال السابق، وهي مدمجة مع مكتبات JavaScript لبرامج WebRTC:

  • webRTC.io هي إحدى أولى مكتبات التجريد لـ WebRTC.
  • Signalmaster هو خادم إشارات تم إنشاؤه لاستخدامه مع مكتبة برامج SimpleWebRTC JavaScript.

إذا كنت لا تريد كتابة أي رمز على الإطلاق، تتوفّر منصات WebRTC تجارية كاملة من شركات، مثل vLine وOpenTok وAsterisk.

للعلم، أنشأت شركة Ericsson خادم إشارات باستخدام PHP على Apache في الأيام الأولى من WebRTC. هذه الطريقة قديمة بعض الشيء، ولكن يجدر إلقاء نظرة على الرمز إذا كنت تفكّر في شيء مشابه.

أمان إرسال الإشارات

"الأمان هو فنّ منع حدوث أي شيء."

سلمان رشدي

التشفير إلزامي لجميع مكوّنات WebRTC.

ومع ذلك، لا تحدّد معايير WebRTC آليات الإشارة، لذا يعود إليك اتّخاذ الإجراءات اللازمة لضمان أمان الإشارة. إذا تمكّن المهاجم من اختراق الإشارات، يمكنه إيقاف الجلسات وإعادة توجيه الاتصالات وتسجيل المحتوى أو تعديله أو إدخاله.

أهم عامل في تأمين الإشارات هو استخدام بروتوكولات آمنة، مثل HTTPS وWSS (على سبيل المثال، TLS)، ما يضمن عدم إمكانية اعتراض الرسائل بدون تشفير. يجب أيضًا الحرص على عدم بث رسائل الإشارة بطريقة يمكن للمتصلين الآخرين الوصول إليها باستخدام خادم الإشارة نفسه.

بعد إرسال الإشارة: استخدام ICE للتعامل مع NAT وجدران الحماية

بالنسبة إلى إشارات البيانات الوصفية، تستخدم تطبيقات WebRTC خادمًا وسيطًا، ولكن بالنسبة إلى بث الوسائط والبيانات الفعلي بعد إنشاء جلسة، تحاول RTCPeerConnection ربط العملاء مباشرةً أو من نظير إلى نظير.

في عالم أبسط، سيكون لكل نقطة نهاية WebRTC عنوان فريد يمكنها تبادله مع الأجهزة الأخرى للتواصل مباشرةً.

اتصال بسيط بين الأجهزة
عالم بدون NAT وجدران الحماية

في الواقع، تعمل معظم الأجهزة خلف طبقة واحدة أو أكثر من NAT، وبعضها مزوّد ببرامج مكافحة الفيروسات التي تحظر منافذ وبروتوكولات معيّنة، والعديد منها يعمل خلف خوادم وكيل وجدران حماية خاصة بالشركات. قد يتم في الواقع تنفيذ جدار الحماية وNAT بواسطة الجهاز نفسه، مثل جهاز توجيه Wi-Fi منزلي.

الأجهزة النظيرة المحمية بجدران حماية وNAT
العالم الحقيقي

يمكن لتطبيقات WebRTC استخدام إطار عمل ICE للتغلّب على تعقيدات الشبكات في العالم الحقيقي. لإتاحة ذلك، يجب أن يمرّر تطبيقك عناوين URL لخادم ICE إلى RTCPeerConnection، كما هو موضّح في هذه المقالة.

يحاول بروتوكول ICE العثور على أفضل مسار لربط الأجهزة النظيرة. وتجرّب جميع الاحتمالات بالتوازي وتختار الخيار الأكثر فعالية. يحاول بروتوكول ICE أولاً إنشاء اتصال باستخدام عنوان المضيف الذي تم الحصول عليه من نظام تشغيل الجهاز وبطاقة الشبكة. إذا تعذّر ذلك (وهو ما سيحدث للأجهزة التي تستخدم NAT)، يحصل بروتوكول ICE على عنوان خارجي باستخدام خادم STUN، وإذا تعذّر ذلك، يتم توجيه حركة البيانات من خلال خادم ترحيل TURN.

بعبارة أخرى، يتم استخدام خادم STUN للحصول على عنوان شبكة خارجية، ويتم استخدام خوادم TURN لنقل البيانات إذا تعذّر الاتصال المباشر (من نظير إلى نظير).

يتوافق كل خادم TURN مع STUN. خادم TURN هو خادم STUN يتضمّن وظيفة ترحيل مدمجة إضافية. تتعامل بروتوكولات ICE أيضًا مع تعقيدات إعدادات NAT. في الواقع، قد تتطلّب عملية NAT hole-punching أكثر من مجرد عنوان IP:port عام.

تحدّد إحدى تطبيقات WebRTC (اختياريًا) عناوين URL لخوادم STUN و/أو TURN في كائن الإعداد iceServers الذي يمثّل الوسيطة الأولى للدالة الإنشائية RTCPeerConnection. بالنسبة إلى appr.tc، تبدو هذه القيمة على النحو التالي:

{
  'iceServers': [
    {
      'urls': 'stun:stun.l.google.com:19302'
    },
    {
      'urls': 'turn:192.158.29.39:3478?transport=udp',
      'credential': 'JZEOEt2V3Qb0y27GRntt2u2PAYA=',
      'username': '28224511:1379330808'
    },
    {
      'urls': 'turn:192.158.29.39:3478?transport=tcp',
      'credential': 'JZEOEt2V3Qb0y27GRntt2u2PAYA=',
      'username': '28224511:1379330808'
    }
  ]
}

بعد أن يحصل RTCPeerConnection على هذه المعلومات، سيتم تلقائيًا تنفيذ عملية ICE السحرية. تستخدم RTCPeerConnection إطار عمل ICE لتحديد أفضل مسار بين الأجهزة المتصلة، وتعمل مع خوادم STUN وTURN حسب الحاجة.

STUN

توفّر شبكات NAT للجهاز عنوان IP لاستخدامه داخل شبكة محلية خاصة، ولكن لا يمكن استخدام هذا العنوان خارجيًا. بدون عنوان عام، لا يمكن لأجهزة WebRTC المتصلة ببعضها البعض التواصل. لحلّ هذه المشكلة، تستخدم WebRTC STUN.

تتوفّر خوادم STUN على الإنترنت العام ولديها مهمة بسيطة واحدة، وهي التحقّق من عنوان IP:port لطلب وارد (من تطبيق يعمل خلف NAT) وإرسال هذا العنوان مرة أخرى كاستجابة. بعبارة أخرى، يستخدم التطبيق خادم STUN لاكتشاف عنوان IP:port من منظور عام. تتيح هذه العملية لجهاز WebRTC نظير الحصول على عنوان متاح للجميع ثم تمريره إلى جهاز نظير آخر من خلال آلية إرسال إشارات من أجل إعداد رابط مباشر. (في الواقع، تعمل شبكات NAT المختلفة بطرق مختلفة وقد تكون هناك طبقات NAT متعددة، ولكن يبقى المبدأ كما هو).

لا تحتاج خوادم STUN إلى تنفيذ الكثير من العمليات أو تذكُّر الكثير من المعلومات، لذا يمكن لخوادم STUN ذات المواصفات المنخفضة نسبيًا التعامل مع عدد كبير من الطلبات.

تنجح معظم مكالمات WebRTC في إنشاء اتصال باستخدام STUN، وذلك بنسبة% 86 وفقًا لموقع Webrtcstats.com، على الرغم من أنّ هذه النسبة قد تكون أقل بالنسبة إلى المكالمات بين الأجهزة التي تستخدم جدران الحماية وإعدادات NAT المعقّدة.

الاتصال من نظير إلى نظير باستخدام خادم STUN
استخدام خوادم STUN للحصول على عناوين IP:port العامة

TURN

يحاول RTCPeerConnection إعداد اتصال مباشر بين الأجهزة المتصلة بالشبكة نفسها عبر بروتوكول UDP. إذا تعذّر ذلك، يلجأ RTCPeerConnection إلى بروتوكول TCP. وفي حال تعذُّر ذلك، يمكن استخدام خوادم TURN كحلّ احتياطي لنقل البيانات بين نقاط النهاية.

أكرّر أنّ TURN تُستخدَم لنقل بث الصوت والفيديو والبيانات بين الأجهزة المتصلة، وليس لنقل بيانات الإشارات.

تتضمّن خوادم TURN عناوين متاحة للجميع، لذا يمكن أن تتواصل معها الأجهزة الأخرى حتى لو كانت هذه الأجهزة محمية بجدران حماية أو خوادم وكيل. تتضمّن خوادم TURN مهمة بسيطة من الناحية النظرية، وهي نقل بث. ومع ذلك، تستهلك هذه الخوادم الكثير من معدل نقل البيانات، على عكس خوادم STUN. بعبارة أخرى، يجب أن تكون خوادم TURN أكثر قوة.

الاتصال من نظير إلى نظير باستخدام خادم STUN
الخيارات الكاملة: STUN وTURN والإشارات

يوضّح هذا المخطّط طريقة عمل TURN. لم ينجح بروتوكول STUN وحده، لذا يلجأ كل نظير إلى استخدام خادم TURN.

نشر خوادم STUN وTURN

لأغراض الاختبار، تشغّل Google خادم STUN عامًا، وهو stun.l.google.com:19302، كما هو مستخدَم في appr.tc. بالنسبة إلى خدمة STUN/TURN للإنتاج، استخدِم rfc5766-turn-server. يتوفّر الرمز المصدري لخوادم STUN وTURN على GitHub، حيث يمكنك أيضًا العثور على روابط تؤدي إلى العديد من مصادر المعلومات حول تثبيت الخادم. تتوفّر أيضًا صورة جهاز افتراضي لخدمة Amazon Web Services.

يتوفّر خادم TURN بديل باسم restund، وهو متاح كرمز مصدر ومتاح أيضًا على AWS. في ما يلي تعليمات حول كيفية إعداد ميزة "استئناف" على Compute Engine.

  1. افتح جدار الحماية حسب الحاجة لـ tcp=443 وudp/tcp=3478.
  2. أنشئ أربع آلات افتراضية، واحدة لكل عنوان IP عام، وصورة Standard Ubuntu 12.06.
  3. إعداد إعدادات جدار الحماية المحلي (السماح بأي شيء من أي مكان)
  4. أدوات التثبيت: shell sudo apt-get install make sudo apt-get install gcc
  5. ثبِّت libre من creytiv.com/re.html.
  6. استرجاع restund من creytiv.com/restund.html وفك حزمته./
  7. wget hancke.name/restund-auth.patch ثم طبِّق التعديل باستخدام patch -p1 < restund-auth.patch.
  8. تشغيل make وsudo make install لـ libre وrestund
  9. عدِّل restund.conf بما يتناسب مع احتياجاتك (استبدِل عناوين IP وتأكَّد من أنّها تتضمّن سرًا مشتركًا واحدًا) وانسخها إلى /etc.
  10. نسخ restund/etc/restund إلى /etc/init.d/
  11. ضبط restund:
    1. اضبط LD_LIBRARY_PATH.
    2. نسخ restund.conf إلى /etc/restund.conf
    3. اضبط restund.conf على استخدام الأرقام العشرة الصحيحة. عنوان IP
  12. تشغيل restund
  13. اختبار باستخدام عميل stund من جهاز بعيد: ./client IP:port

ما بعد المحادثات بين شخصين: WebRTC متعدد الأطراف

يمكنك أيضًا الاطّلاع على معيار IETF المقترَح من "جاستن أوبيرتي" بشأن واجهة برمجة تطبيقات REST للوصول إلى خدمات TURN.

من السهل تخيّل حالات استخدام لبث الوسائط تتجاوز مجرد مكالمة بسيطة بين شخصين. على سبيل المثال، مؤتمر فيديو بين مجموعة من الزملاء أو حدث عام يضمّ متحدثًا واحدًا ومئات أو ملايين المشاهدين.

يمكن لتطبيق WebRTC استخدام عدة اتصالات RTCPeerConnection لكي تتصل كل نقطة نهاية بكل نقاط النهاية الأخرى في إعدادات الشبكة المتداخلة. هذا هو النهج الذي تتّبعه تطبيقات، مثل talky.io، وهو يعمل بشكل جيد للغاية مع عدد قليل من الزملاء. بالإضافة إلى ذلك، يصبح استهلاك المعالجة وعرض النطاق الترددي مفرطًا، خاصةً بالنسبة إلى عملاء الأجهزة الجوّالة.

Mesh: مكالمة صغيرة متعددة الأطراف
بنية الشبكة الكاملة: الجميع متصلون بالجميع

بدلاً من ذلك، يمكن لتطبيق WebRTC اختيار نقطة نهاية واحدة لتوزيع عمليات البث على جميع نقاط النهاية الأخرى في إعداد على شكل نجمة. يمكن أيضًا تشغيل نقطة نهاية WebRTC على خادم وإنشاء آلية إعادة توزيع خاصة بك (يوفّر موقع webrtc.org تطبيق عميل نموذجي).

منذ الإصدار 31 من Chrome والإصدار 18 من Opera، يمكن استخدام MediaStream من RTCPeerConnection كإدخال لآخر. يمكن أن يتيح ذلك بنى أكثر مرونة لأنّه يمكّن تطبيق الويب من التعامل مع توجيه المكالمات من خلال اختيار الجهاز الآخر الذي سيتم الاتصال به. لمشاهدة ذلك عمليًا، يمكنك الاطّلاع على عينات WebRTC لعملية نقل اتصال الند للند وعينات WebRTC لعمليات ربط متعددة بين الأجهزة.

وحدة تحكّم متعددة النقاط

يتمثّل الخيار الأفضل لعدد كبير من نقاط النهاية في استخدام وحدة تحكّم متعددة النقاط (MCU). هذا خادم يعمل كجسر لتوزيع الوسائط بين عدد كبير من المشاركين. يمكن لوحدات التحكّم المتعدّدة النقاط التعامل مع درجات الدقة وبرامج الترميز ومعدّلات عرض اللقطات المختلفة في مؤتمر فيديو، ومعالجة تحويل الترميز، وتنفيذ عملية إعادة توجيه انتقائية لمجموعات البث، ودمج أو تسجيل الصوت والفيديو. في المكالمات المتعددة المشاركين، هناك عدد من المشاكل التي يجب مراعاتها، لا سيما كيفية عرض فيديوهات متعددة ودمج الصوت من مصادر متعددة. تحاول منصات السحابة الإلكترونية، مثل vLine، أيضًا تحسين توجيه الزيارات.

يمكنك شراء حزمة أجهزة MCU كاملة أو إنشاء حزمة خاصة بك.

صورة Cisco MCU5300 من الخلف
الجزء الخلفي من وحدة تحكّم متعددة النقاط من Cisco

تتوفّر العديد من خيارات برامج وحدة التحكّم الدقيقة المفتوحة المصدر. على سبيل المثال، تنتج Licode (المعروفة سابقًا باسم Lynckia) وحدة تحكّم متعددة النقاط مفتوحة المصدر لـ WebRTC. تتضمّن OpenTok أداة Mantis.

ما وراء المتصفّحات: نقل الصوت عبر بروتوكول الإنترنت والهواتف والمراسلة

تتيح الطبيعة الموحّدة لـ WebRTC إمكانية إنشاء اتصال بين تطبيق WebRTC يعمل في متصفّح وجهاز أو منصة تعمل على منصة اتصالات أخرى، مثل هاتف أو نظام مؤتمرات فيديو.

SIP هو بروتوكول إشارات تستخدمه أنظمة VoIP واجتماعات الفيديو. لإتاحة التواصل بين تطبيق ويب WebRTC وعميل SIP، مثل نظام مؤتمرات الفيديو، يحتاج WebRTC إلى خادم وكيل للتوسّط في الإشارات. يجب أن تمر الإشارات عبر البوابة، ولكن بعد إنشاء الاتصال، يمكن أن تنتقل حركة بيانات SRTP (الفيديو والصوت) مباشرةً من جهاز إلى آخر.

شبكة الهاتف العامة (PSTN) هي شبكة تحويل الدوائر لجميع الهواتف التناظرية "العادية القديمة". بالنسبة إلى المكالمات بين تطبيقات الويب التي تستخدم WebRTC والهواتف، يجب أن تمرّ حركة البيانات عبر بوابة شبكة الهواتف العامة (PSTN). وبالمثل، تحتاج تطبيقات الويب التي تستخدم WebRTC إلى خادم XMPP وسيط للتواصل مع نقاط نهاية Jingle، مثل برامج المراسلة الفورية. طوّرت Google بروتوكول Jingle كإضافة إلى بروتوكول XMPP لإتاحة الصوت والفيديو لخدمات المراسلة. تستند عمليات تنفيذ WebRTC الحالية إلى مكتبة C++ libjingle، وهي عملية تنفيذ لبروتوكول Jingle تم تطويرها في البداية لبرنامج Talk.

تستفيد مجموعة من التطبيقات والمكتبات والمنصات من قدرة WebRTC على التواصل مع العالم الخارجي:

  • sipML5: برنامج مفتوح المصدر لعميل SIP مكتوب بلغة JavaScript
  • jsSIP: مكتبة JavaScript SIP
  • Phono: واجهة برمجة تطبيقات JavaScript مفتوحة المصدر للهاتف تم إنشاؤها كإضافة
  • Zingaya: أداة هاتف قابلة للتضمين
  • Twilio: الصوت والمراسلة
  • Uberconference: مكالمة فيديو

أنشأ مطوّرو sipML5 أيضًا بوابة webrtc2sip. عرضت شركتا Tethr وTropo إطار عمل للاتصالات في حالات الكوارث "في حقيبة" باستخدام خلية OpenBTS لإتاحة الاتصالات بين الهواتف العادية وأجهزة الكمبيوتر من خلال WebRTC. هذا هو التواصل الهاتفي بدون مشغّل شبكة جوّال.

تعرَّف على مزيد من المعلومات

يقدّم الدرس التطبيقي حول WebRTC تعليمات مفصّلة حول كيفية إنشاء تطبيق للدردشة عبر الفيديو والنص باستخدام خدمة إرسال إشارات Socket.io تعمل على Node.

عرض Google I/O التقديمي حول WebRTC من عام 2013 مع جاستن أوبيرتي، المسؤول التقني عن WebRTC

عرض Chris Wilson التقديمي في SFHTML5 - مقدمة عن تطبيقات WebRTC

يقدّم الكتاب المكوّن من 350 صفحة WebRTC: واجهات برمجة التطبيقات وبروتوكولات RTCWEB للويب في الوقت الفعلي المستند إلى HTML5 الكثير من التفاصيل حول مسارات البيانات والإشارات، ويتضمّن عددًا من الرسومات البيانية التفصيلية لتصميم الشبكة.

‫WebRTC والإشارات: ما تعلّمناه خلال عامَين: مشاركة مدوّنة TokBox حول سبب كون استبعاد الإشارات من المواصفات فكرة جيدة

يقدّم كتاب Ben Strong A Practical Guide to Building WebRTC Apps الكثير من المعلومات حول تصميمات WebRTC وبنيتها الأساسية.

يتناول فصل WebRTC في كتاب High Performance Browser Networking لإيليا غريغوريك بالتفصيل بنية WebRTC وحالات الاستخدام والأداء.