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

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

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

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

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

لماذا لا يتم تحديد الإشارة من خلال WebRTC؟

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

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

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

يتطلّب JSEP التبديل بين نظيرَي offer وanswer، وهما البيانات الوصفية للوسائط المذكورة أعلاه. ويتم تقديم العروض والإجابات بتنسيق بروتوكول وصف الجلسة (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 API وأنظمة الإشارات: العرض والإجابات والمرشح

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

ولإعداد هذه العملية، هناك مهمتان في "RTCPeerConnection":

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

بعد التحقق من هذه البيانات المحلية، يجب تبادلها مع النظير البعيد من خلال آلية إشارة.

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

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

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

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

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

رمز 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.

استكشاف التطبيقات المشابهة

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

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

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

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

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

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

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

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

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

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

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

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

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

قياس الإشارات

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

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

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

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

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

(يقدّم دليل تكنولوجيا الويب في الوقت الفعلي من مطوّر Phil Leggetter قائمة شاملة بخدمات المراسلة والمكتبات).

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

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

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

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

إليك العميل index.html:

<!DOCTYPE html>
<html>
  <head>
    <title>WebRTC client</title>
  </head>
  <body>
    <script src='/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 وSocket.IO وnode-static. يمكن تنزيل العُقدة من Node.js (التثبيت واضح وسريع). لتثبيت Socket.IO وNode-static، شغِّل "إدارة حزمة العُقد" من وحدة طرفية في دليل التطبيق:

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 هو خادم إشارة تم إنشاؤه للاستخدام مع مكتبة برامج JavaScript SimpleWebRTC.

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

للاحتفاظ بنسخة احتياطية، أنشأت شركة 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، وفي حال تعذُّر ذلك، يتم توجيه حركة البيانات عبر خادم ترحيل T.

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

يتوافق كل خادم من خوادم Current مع STUN. إنّ خادم Current هو خادم STUN ذي وظيفة نقل إضافية مدمجة. يتعامل ICE أيضًا مع تعقيدات إعدادات NAT. في الواقع، قد يتطلب ثقب NAT على الحائط أكثر من مجرد عنوان IP الخاص بمنفذ عام.

يتم (اختياريًا) تحديد عناوين URL لخوادم STUN و/أو Current من خلال تطبيق WebRTC في كائن الإعداد 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 وCurrent عند الضرورة.

صِنج

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

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

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

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

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

انعطاف

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

وللتأكيد، يُستخدم التحول في نقل الصوت والفيديو وبث البيانات بين التطبيقات المشابهة، وليس من خلال الإشارة إلى البيانات.

لدى خوادم turn عناوين عامة، بحيث يمكن الاتصال بها من قبل النظراء حتى لو كان الأقران وراء جدران الحماية أو الوكيل. إنّ مهمة التحول إلى الخوادم هي مهمة بسيطة من الناحية النظرية، وهي ترحيل البث. وعلى عكس خوادم STUN، فهي تستهلك بطبيعتها الكثير من معدل نقل البيانات. بمعنى آخر، يجب أن تكون خوادم Current أكثر أمانًا.

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

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

نشر خادمَي STUN وCurrent

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

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

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

ميزات أخرى غير مباشرة: WebRTC المتعددة الأطراف

يمكنك أيضًا إلقاء نظرة على معيار IETF المقترَح من "جاستن أوبرتي" بشأن REST API للوصول إلى خدمات turn.

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

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

الشبكة المتداخلة: مكالمة صغيرة على شكل حرف N
بنية الشبكة المتداخلة بالكامل: الجميع متصلون بالجميع

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

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

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

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

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

منظر خلفي لجهاز Cisco MCU5300
الجزء الخلفي من Cisco MCU

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

تطبيقات أخرى: بروتوكول الصوت على الإنترنت والهواتف والمراسلة

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

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

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

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

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

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

التعرف على المزيد

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

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

العرض التقديمي لكريس ويلسون SFHTML5 - مقدمة حول تطبيقات WebRTC

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

WebRTC and Signaling: What two Years Has Taught Us - مشاركة مدونة على TokBox حول عدم اعتبار أنّ استخدام الإشارات خارج المواصفات فكرة جيدة.

Ben Strong's دليل عملي لإنشاء تطبيقات WebRTC يوفر الكثير من المعلومات حول مخططات WebRTC والبنية الأساسية.

يتعمق فصل WebRTC في Ilya Grigorik شبكات المتصفح العالية الأداء في بنية WebRTC وحالات الاستخدام والأداء.