שליחת נתונים בין דפדפנים עם ערוצי נתונים WebRTC

שליחת נתונים בין שני דפדפנים לצורך תקשורת, משחקים או העברת קבצים יכולה להיות תהליך מורכב למדי. כדי לעשות זאת, צריך להגדיר שרת להעברת נתונים ולשלם עליו, ואולי גם להתאים את התהליך למספר מרכזי נתונים. בתרחיש הזה, ייתכן זמן אחזור ארוך וקשה לשמור על פרטיות הנתונים.

אפשר לצמצם את הבעיות האלה באמצעות שימוש ב-API‏ RTCDataChannel של WebRTC כדי להעביר נתונים ישירות מצד אחד לשני. במאמר הזה נסביר את העקרונות הבסיסיים של הגדרת ערוצי נתונים ושימוש בהם, וגם את תרחישים לדוגמה הנפוצים באינטרנט כיום.

למה עוד ערוץ נתונים?

יש לנו WebSocket,‏ AJAX ו-Server Sent Events. למה אנחנו צריכים ערוץ תקשורת נוסף? WebSocket הוא דו-כיווני, אבל כל הטכנולוגיות האלה מיועדות לתקשורת אל שרת או משרת.

RTCDataChannel משתמשת בגישה שונה:

  • הוא פועל עם ממשק ה-API של RTCPeerConnection, שמאפשר קישוריות מקצה לקצה. כך אפשר לצמצם את זמן האחזור – אין שרת ביניים ופחות 'קפיצות'.
  • RTCDataChannel משתמש ב-Stream Control Transmission Protocol‏ (SCTP), שמאפשר הגדרה של סמנטיקה של העברה מחוץ לסדר והגדרה של שליחה חוזרת.

RTCDataChannel זמין עכשיו עם תמיכה ב-SCTP במחשב וב-Android בדפדפנים Google Chrome,‏ Opera ו-Firefox.

אזהרה: איתות, STUN ו-TURN

WebRTC מאפשר תקשורת בין שווים, אבל עדיין נדרשים שרתים לאיתור כדי להחליף מטא-נתונים של מדיה ורשתות כדי להתחיל חיבור בין שווים.

WebRTC מתמודד עם NAT וחומות אש באמצעות:

  • מסגרת ICE כדי לקבוע את נתיב הרשת הטוב ביותר האפשרי בין שווים.
  • שרתי STUN – כדי לקבוע כתובת IP ויציאה נגישים לציבור של כל אפליקציה להשוואה.
  • שרתי TURN אם החיבור הישיר נכשל ונדרש העברת נתונים.

למידע נוסף על האופן שבו WebRTC פועל עם שרתים לצורכי איתות ורשתות, אפשר לעיין במאמר WebRTC בעולם האמיתי: STUN,‏ TURN ואיתות.

היכולות

ה-API של RTCDataChannel תומך בקבוצה גמישה של סוגי נתונים. ה-API תוכנן לחקות את WebSocket בדיוק, ו-RTCDataChannel תומך במחרוזות וגם בחלק מהסוגים הבינאריים ב-JavaScript, כמו Blob,‏ ArrayBuffer ו-ArrayBufferView. הסוגים האלה יכולים להיות מועילים כשעובדים עם העברת קבצים ומשחקים מרובי משתתפים.

RTCDataChannel יכול לפעול במצב לא מהימן ולא מסודר (בדומה לפרוטוקול User Datagram או ל-UDP), במצב מהימן ומאורגן (בדומה ל-Transmission Control Protocol או TCP), ובמצבים מהימנים חלקיים:

  • המצב 'מהימן ומסודר' מבטיח את העברת ההודעות ואת הסדר שבו הן נמסרות. הפעולה הזו דורשת תקורה נוספת, ולכן יכול להיות שהמצב הזה יהיה איטי יותר.
  • במצב לא מהימן ולא מסודר אין ערובה שכל ההודעות יגיעו לצד השני, או באיזה סדר הן יגיעו. כך אפשר להסיר את התקורה, וכך המצב הזה פועל מהר יותר.
  • המצב 'אמין חלקית' מבטיח את העברת ההודעה בתנאים ספציפיים, כמו זמן קצוב לשליחת ההודעה מחדש או מספר מקסימלי של שליחות חוזרות. אפשר גם להגדיר את סדר ההודעות.

הביצועים בשני המצבים הראשונים זהים כמעט, אם אין אובדן מנות. עם זאת, במצב מהימן ומסודר, חבילה שאבדה גורמת לחסימה של חבילות אחרות שמגיעות אחריה, וייתכן שהחבילה שאבדה תהיה לא רלוונטית עד שהיא תישלח מחדש ותגיע. כמובן שאפשר להשתמש בכמה ערוצי נתונים בתוך אותה אפליקציה, לכל אחד מהם סמנטיקה מהימנה או לא מהימנה.

הטבלה הבאה מבוססת על רשת דפדפן עם ביצועים גבוהים מאת Ilya Graigorik:

TCPUDPSCTP
אמינותאמיןהמידע לא אמיןניתן להגדרה
משלוחהזמנה שלללא סדרניתן להגדרה
הפצהמבוססת-בייטהודעותהודעות
בקרת זרימהכןלאכן
בקרת עומסכןלאכן

בשלב הבא תלמדו איך להגדיר את RTCDataChannel לשימוש במצב מהימן ומסודר או במצב לא מהימן ולא מסודר.

הגדרת ערוצי נתונים

יש כמה הדגמות פשוטות של RTCDataChannel באינטרנט:

בדוגמאות האלה, הדפדפן יוצר חיבור עמית לעצמו, ואז יוצר ערוץ נתונים ושולח הודעה דרך חיבור העמית. לאחר מכן, הוא יוצר ערוץ נתונים ושולח את ההודעה דרך החיבור לצד השני. בסוף, ההודעה תופיע בתיבה בצד השני של הדף.

הקוד הנדרש כדי להתחיל הוא קצר:

const peerConnection = new RTCPeerConnection();

// Establish your peer connection using your signaling channel here
const dataChannel =
  peerConnection.createDataChannel("myLabel", dataChannelOptions);

dataChannel.onerror = (error) => {
  console.log("Data Channel Error:", error);
};

dataChannel.onmessage = (event) => {
  console.log("Got Data Channel Message:", event.data);
};

dataChannel.onopen = () => {
  dataChannel.send("Hello World!");
};

dataChannel.onclose = () => {
  console.log("The Data Channel is Closed");
};

האובייקט dataChannel נוצר מחיבור שכבר הוקם בין שווים. אפשר ליצור אותו לפני או אחרי שהאות מתבצע. לאחר מכן מעבירים תווית כדי להבדיל את הערוץ הזה מערוצים אחרים וקבוצה של הגדרות אישיות אופציונליות:

const dataChannelOptions = {
  ordered: false, // do not guarantee order
  maxPacketLifeTime: 3000, // in milliseconds
};

אפשר גם להוסיף את האפשרות maxRetransmits (מספר הפעמים לניסיון לפני הכשל), אבל אפשר לציין רק את maxRetransmits או את maxPacketLifeTime, ולא את שניהם. לסמנטיקה של UDP, מגדירים את maxRetransmits כ-0 ואת ordered כ-false. מידע נוסף זמין במזהי IETF הבאים: פרוטוקול העברת בקרה בסטרימינג ותוסף אמינות חלקית לפרוטוקול שידור Control Transmission.

  • ordered: אם ערוץ הנתונים מבטיח שהסדר יהיה בסדר או לא
  • maxPacketLifeTime: משך הזמן המקסימלי לנסות לשלוח מחדש הודעה שנכשלה
  • maxRetransmits: מספר הפעמים המקסימלי לניסיון לשדר מחדש הודעה שנכשלה
  • protocol: מאפשר שימוש בפרוטוקול משנה שמספק מטא מידע כלפי האפליקציה
  • negotiated: אם ההגדרה היא true, המערכת לא תגדיר באופן אוטומטי ערוץ נתונים בצד השני, ותצטרכו ליצור ערוץ נתונים עם אותו מזהה בצד השני בעצמכם.
  • id: מאפשר לכם לספק מזהה משלכם לערוץ, שאפשר להשתמש בו רק בשילוב עם negotiated שמוגדר כ-true)

רוב האנשים צריכים להשתמש רק בשלוש האפשרויות הראשונות: ordered,‏ maxPacketLifeTime ו-maxRetransmits. ב-SCTP (שכל הדפדפנים שתומכים ב-WebRTC משתמשים בו עכשיו) הערכים 'מהימן' ו'מסודר' מוגדרים כ-true כברירת מחדל. אם אתם רוצים שליטה מלאה משכבת האפליקציות, כדאי להשתמש בנתונים לא מהימנים או לא מסודרים, אבל ברוב המקרים כדאי להשתמש באמינות חלקית.

שימו לב שכמו ב-WebSocket, RTCDataChannel יוצר אירועים כשמתבצע חיבור, כשהחיבור נסגר או כשיש שגיאות, וכשהוא מקבל הודעה מהצינור השני.

זה בטוח?

הצפנה היא חובה בכל הרכיבים של WebRTC. ב-RTCDataChannel, כל הנתונים מאובטחים באמצעות Transport Layer Security ל-Datagram‏ (DTLS). DTLS הוא נגזר של SSL, כלומר, הנתונים יהיו מאובטחים כמו כל חיבור סטנדרטי מבוסס SSL. DTLS הוא תקן מובנה בכל הדפדפנים שתומכים ב-WebRTC. מידע נוסף זמין ב-Wireshark wiki.

שינוי האופן שבו אתם חושבים על נתונים

טיפול בכמויות גדולות של נתונים יכול להיות נקודת חולשה ב-JavaScript. כפי שציינו המפתחים של Sharefest, כדי לעשות זאת נדרשה חשיבה חדשה על נתונים. אם אתם מעבירים קובץ גדול יותר מנפח הזיכרון הפנוי, תצטרכו לחשוב על דרכים חדשות לשמירת המידע הזה. כאן נכנסים לתמונה טכנולוגיות, כמו FileSystem API, כפי שמוצג בהמשך.

פיתוח אפליקציה לשיתוף קבצים

עכשיו אפשר ליצור אפליקציית אינטרנט שיכולה לשתף קבצים בדפדפן באמצעות RTCDataChannel. פיתוח על גבי RTCDataChannel אומר שנתוני הקבצים המועברים מוצפנים ולא נוגעים לשרתים של ספק האפליקציה. הפונקציונליות הזו, בשילוב עם האפשרות להתחבר למספר לקוחות כדי לשתף מהר יותר, הופכת את שיתוף הקבצים ב-WebRTC לאפשרות חזקה באינטרנט.

כדי שההעברה תושלם בהצלחה, צריך לבצע כמה שלבים:

  1. קריאת קובץ ב-JavaScript באמצעות File API.
  2. ליצור חיבור בין לקוחות באמצעות RTCPeerConnection.
  3. יצירת ערוץ נתונים בין לקוחות באמצעות RTCDataChannel.

יש כמה נקודות שכדאי לזכור כשמנסים לשלוח קבצים דרך RTCDataChannel:

  • גודל הקובץ: אם גודל הקובץ קטן יחסית וניתן לאחסן אותו ולטעון אותו כ-Blob אחד, אפשר לטעון אותו לזיכרון באמצעות File API ואז לשלוח את הקובץ כפי שהוא דרך ערוץ מהימן (עם זאת, חשוב לזכור שבדפדפנים יש מגבלות על גודל ההעברה המקסימלי). ככל שגודל הקובץ גדול יותר, הדברים נעשים מורכבים יותר. כשנדרש מנגנון חלוקה למקטעים, מטעינים את מקטעי הקובץ ושולחים אותם לשותף אחר, יחד עם המטא-נתונים של chunkID כדי שהשותף יוכל לזהות אותם. חשוב לזכור שבמקרה כזה, צריך גם לשמור את הקטעים קודם באחסון אופליין (לדוגמה, באמצעות FileSystem API) ולשמור אותם בדיסק של המשתמש רק כשהקובץ נמצא במלואו.
  • גודל מקטע: אלה 'האטומים' הקטנים ביותר של הנתונים באפליקציה. חלוקה למקטעים נדרשת כי יש כרגע מגבלת גודל לשליחה (הבעיה הזו תיפתר בגרסה עתידית של ערוצי הנתונים). ההמלצה הנוכחית לגבי גודל מקטע מקסימלי היא 64KiB.

אחרי שהקובץ יועבר במלואו לצד השני, תוכלו להוריד אותו באמצעות תג עוגן:

function saveFile(blob) {
  const link = document.createElement('a');
  link.href = window.URL.createObjectURL(blob);
  link.download = 'File Name';
  link.click();
};

אפליקציות שיתוף הקבצים האלה ב-PubShare וב-GitHub משתמשות בשיטה הזו. שניהם בקוד פתוח ומספקים בסיס טוב לאפליקציית שיתוף קבצים שמבוססת על RTCDataChannel.

אז מה אפשר לעשות?

RTCDataChannel פותח דרכים חדשות לפתח אפליקציות לשיתוף קבצים, למשחקים מרובי משתתפים ולמסירת תוכן.

  • שיתוף קבצים בין משתמשים (P2P) כפי שמתואר למעלה
  • משחקים מרובי משתתפים בשילוב עם טכנולוגיות אחרות, כמו WebGL, כפי שמוצג ב-BananaBread של Mozilla
  • העברת תוכן לפי המצאה מחדש של PeerCDN, מסגרת שמספקת נכסי אינטרנט באמצעות תקשורת נתונים מקצה לקצה (PeerCDN)

שינוי הדרך שבה אתם בונים אפליקציות

עכשיו אתם יכולים לספק אפליקציות שמעוררות יותר עניין באמצעות חיבורים עם ביצועים גבוהים וזמן אחזור קצר דרך RTCDataChannel. מסגרות כמו PeerJS ו-PubNub WebRTC SDK מאפשרות להטמיע את RTCDataChannel בקלות רבה יותר, ול-API יש עכשיו תמיכה רחבה בכל הפלטפורמות.

ההשקה של RTCDataChannel יכולה לשנות את האופן שבו אתם חושבים על העברת נתונים בדפדפן.

למידע נוסף