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

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

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

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

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

RTCDataChannel נוקטת גישה שונה:

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

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

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

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

פרוטוקול WebRTC מתמודד עם NAT וחומות אש באמצעות:

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

למידע נוסף על האופן שבו WebRTC פועל עם שרתים לאיתות ולרשתות, אפשר לעיין במאמר WebRTC inthe real world: STUN, TURN, and signaling.

היכולות

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

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

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

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

הטבלה הבאה מתוך הספר High Performance Browser Networking של Ilya Grigorik יכולה לעזור:

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. מידע נוסף זמין ב-RFC של IETF: ‏ Stream Control Transmission Protocol ו-Stream Control Transmission Protocol Partial Reliability Extension.

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

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

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

זה בטוח?

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

שינוי הגישה לנתונים

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

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

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

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

  1. קוראים קובץ ב-JavaScript באמצעות File API.
  2. יצירת חיבור בין עמיתים (P2P) בין לקוחות באמצעות 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, מסגרת שמעבירה נכסי אינטרנט באמצעות תקשורת נתונים בין עמיתים

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

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

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

למידע נוסף