נעים להכיר: WebSockets – הוספת שקעים לאינטרנט

הבעיה: זמן אחזור קצר חיבורים לשרת-לקוח ולשרת-לקוח

האינטרנט נבנה בעיקר סביב הפרדיגמה 'בקשה/תשובה' של HTTP. לקוח טוען דף אינטרנט ואז לא קורה כלום עד שהמשתמש לוחץ ועובר לדף הבא. בסביבות שנת 2005, AJAX החל לגרום לאינטרנט להרגיש דינמי יותר. עם זאת, כל תקשורת ה-HTTP יובאה על ידי הלקוח, דבר שדרש אינטראקציה של המשתמש או סקרים תקופתיים כדי לטעון נתונים חדשים מהשרת.

טכנולוגיות שמאפשרות לשרת לשלוח נתונים ללקוח ברגע שהוא יודע שנתונים חדשים זמינים, קיימות לא מעט זמן. הם נקראים שמות כגון 'דחיפה' או 'שביט'. אחת מהפריצות הנפוצות ביותר ליצירת אשליה של חיבור ביוזמת השרת נקראת 'דגימה ארוכה'. בסקרים ארוכים, הלקוח פותח חיבור HTTP לשרת שמשאיר אותו פתוח עד לשליחת התגובה. בכל פעם שבשרת יש נתונים חדשים, הוא שולח את התגובה (טכניקות אחרות כוללות בקשות Flash, בקשות XHR מרובות חלקים כך שנקראות htmlfiles). סקרים ארוכים ושאר השיטות עובדות היטב. אתם משתמשים בהם מדי יום באפליקציות כמו צ'אט של GMail.

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

היכרות עם WebSocket: הצגת sockets לאינטרנט

במפרט WebSocket מוגדר ממשק API שיוצר חיבורי "socket" בין דפדפן אינטרנט לשרת. במילים פשוטות: יש חיבור מתמשך בין הלקוח לשרת, ושני הצדדים יכולים להתחיל לשלוח נתונים בכל שלב.

תחילת העבודה

אתה פותח חיבור WebSocket פשוט על ידי קריאה ל-WebSocket constructor:

var connection = new WebSocket('ws://html5rocks.websocket.org/echo', ['soap', 'xmpp']);

שימו לב לws:. זוהי הסכימה החדשה של כתובות URL לחיבורי WebSocket. יש גם את האפשרות wss: לחיבור מאובטח של WebSocket, באותו האופן שבו https: משמש לחיבורי HTTP מאובטחים.

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

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

השמות של פרוטוקולי המשנה צריכים להיות אחד מהשמות של פרוטוקולי המשנה הרשומים במרשם IANA. נכון לעכשיו יש רק שם אחד של פרוטוקול משנה (סבון) שרשום בפברואר 2012.

// When the connection is open, send some data to the server
connection.onopen = function () {
connection.send('Ping'); // Send the message 'Ping' to the server
};

// Log errors
connection.onerror = function (error) {
console.log('WebSocket Error ' + error);
};

// Log messages from the server
connection.onmessage = function (e) {
console.log('Server: ' + e.data);
};

תקשורת עם השרת

ברגע שיש לנו חיבור לשרת (כשהאירוע open מופעל), אנחנו יכולים להתחיל לשלוח נתונים לשרת באמצעות השיטה send('your message') באובייקט החיבור. בעבר היא תמכה רק במחרוזות, אבל לפי המפרט העדכני ביותר, היא יכולה עכשיו גם לשלוח הודעות בינאריות. כדי לשלוח נתונים בינאריים, אפשר להשתמש באובייקט Blob או ArrayBuffer.

// Sending String
connection.send('your message');

// Sending canvas ImageData as ArrayBuffer
var img = canvas_context.getImageData(0, 0, 400, 320);
var binary = new Uint8Array(img.data.length);
for (var i = 0; i < img.data.length; i++) {
binary[i] = img.data[i];
}
connection.send(binary.buffer);

// Sending file as Blob
var file = document.querySelector('input[type="file"]').files[0];
connection.send(file);

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

WebSocket יכול גם לקבל הודעות בינאריות במפרט העדכני ביותר. אפשר לקבל פריימים בינאריים בפורמט Blob או ArrayBuffer. כדי לציין את הפורמט של הקובץ הבינארי שהתקבל, צריך להגדיר את המאפיין BigQueryType של אובייקט WebSocket ל-blob או ל-arraybuffer'. פורמט ברירת המחדל הוא blob. (אין צורך להתאים את הפרמטרBinaryType בעת השליחה).

// Setting binaryType to accept received binary as either 'blob' or 'arraybuffer'
connection.binaryType = 'arraybuffer';
connection.onmessage = function(e) {
console.log(e.data.byteLength); // ArrayBuffer object if binary
};

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

// Determining accepted extensions
console.log(connection.extensions);

תקשורת בין מקורות

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

שרתי Proxy

כל טכנולוגיה חדשה מגיעה עם קבוצה חדשה של בעיות. במקרה של WebSocket זו תאימות לשרתי proxy לתיווך חיבורי HTTP ברוב רשתות החברה. פרוטוקול WebSocket משתמש במערכת שדרוג HTTP (שבה משתמשים בדרך כלל ב-HTTP/SSL) כדי 'לשדרג' חיבור HTTP לחיבור WebSocket. חלק משרתי ה-proxy לא אוהבים את זה והם ינתקו את החיבור. לכן, גם אם לקוח מסוים משתמש בפרוטוקול WebSocket, ייתכן שלא ניתן יהיה ליצור חיבור. זה יפגע עוד יותר בקטע הבא :)

כדאי להשתמש ב-WebSockets עוד היום

WebSocket היא עדיין טכנולוגיה צעירה ולא מיושמת באופן מלא בכל הדפדפנים. עם זאת, ניתן להשתמש ב-WebSocket כבר היום עם ספריות שמשתמשות באחת מהחלופות שצוינו למעלה בכל פעם ש-WebSocket לא זמין. ספרייה מאוד פופולרית בדומיין הזה היא socket.io.הספרייה הזו כוללת לקוח ושרת של הפרוטוקול, והיא כוללת חלופות (החל מפברואר 2012 אין תמיכה בהעברת הודעות בינאריות). יש גם פתרונות מסחריים כמו PusherApp, שאפשר לשלב בקלות בכל סביבת אינטרנט באמצעות ממשק API של HTTP לשליחת הודעות WebSocket ללקוחות. בגלל בקשת ה-HTTP הנוספת, תמיד תהיה תקורה נוספת בהשוואה ל-WebSocket טהור.

בצד השרת

השימוש ב-WebSocket יוצר דפוס שימוש חדש לגמרי עבור אפליקציות בצד השרת. למרות שמחסניות שרת מסורתיים כגון LAMP תוכננו סביב מחזור הבקשה/תגובה של HTTP, הן בדרך כלל לא מתמודדות היטב עם מספר גדול של חיבורי WebSocket פתוחים. כדי לשמור על מספר גדול של חיבורים פתוחים בו-זמנית, יש צורך בארכיטקטורה שמקבלת בו-זמניות גבוהה בעלות ביצועים נמוכה. ארכיטקטורות כאלה מתוכננות בדרך כלל סביב Threading או כאלה שנקראים IO ללא חסימה.

הטמעות בצד השרת

גרסאות פרוטוקול

מעכשיו, פרוטוקול הכבלים (לחיצת יד והעברת הנתונים בין הלקוח לשרת) עבור WebSocket הוא RFC6455. הגרסה העדכנית ביותר של Chrome ו-Chrome ל-Android תואמים בצורה מלאה ל-RFC6455, כולל העברת הודעות בינאריות. בנוסף, Firefox יהיה תואם לגרסה 11, Internet Explorer בגרסה 10. אפשר עדיין להשתמש בגרסאות פרוטוקול ישנות יותר, אבל זה לא מומלץ כי הן ידועות כפגיעות. אם יש לכם הטמעות שרת לגרסאות ישנות יותר של פרוטוקול WebSocket, מומלץ לשדרג אותו לגרסה העדכנית.

תרחישים לדוגמה

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

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

הדגמות

קובצי עזר