מדריך Node.js: שימוש ב-socket.io

כך כותבים אפליקצית Node.js ו-sockets.
Node.js Logo

במאמר הקודם למדנו על npm ועל איך מתקינים מודולים חיצוניים. במאמר הזה אנחנו נדבר קצת על עבודה עם מודולים חיצוניים ובחרתי ב-socket.io. למה? כי יש המון מודולים מצוינים ומשובחים שם בחוץ וצריך לבחור אחד, אז בחרתי בזה. יש מודולים (express למשל) שמצריכים מדריך משל עצמם. socket.io הוא אחד כזה, יש לו לא מעט אפשרויות שמפורטות בדוקומנטציה שלו. אני פשוט אבחר מקרה לשימוש ואשתמש בו כדי להדגים דרך עבודה.

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

אחד הניסויים של שי היה ליצור שעון שמתעדכן כל שניה שמציג את זמן האמת בשרת באמצעות Node.js. את זה שי עשה באמצעות שרת http שפשוט לא סוגר את ה-response וממשיך לטעון את הדף.

אנחנו נעשה את אותו הדבר, אבל עם websocket ו-socket.io. האמת היא שיחסית למודולים שעסקנו בהם, socket.io הוא מאוד פשוט. יש גם הסברים בדוקומנטציה שלו (שהיא לא רעה). על מנת לשדר מידע, כל מה שאנחנו צריכים זה ליצור שרת http רגיל, להעביר אותו ל-io באמצעות ה-require ואז פשוט ליצור event ל-connection ולעשות emit למידע.

נשמע מסובך? ממש ממש לא! הנה:


var app = require('http').createServer(handler) 
var io = require('socket.io')(app);

io.on('connection', function (socket) {
    socket.emit('some-event', 'some-data');
});

ובצד הלקוח?

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


        <script src="https://cdn.socket.io/socket.io-1.1.0.js"></script>
        <script>
          var socket = io.connect('http://localhost');
          socket.on('clock-event', function (data) {
            document.write(data);
          });
        </script>

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

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


/**
Creating the server object. launch the createServer method and the handler as the callback.
The handler is being fired rght after
**/
var app = require('http').createServer(handler) 
var io = require('socket.io')(app);
var fs = require('fs'); //We need fs to call index.html

app.listen(3000); //Listening on port 3000. change it to 80 if you don't have Apache

/**
Callback that fired when http.createServer completed

var req = the request.
var res = the result.
**/
function handler (req, res) {
  fs.readFile(__dirname + '/index.html', //reading the file
  function (err, data) {  //callback that get fired right after the file was created
    if (err) { //if callback return error.
      res.writeHead(500);
      return res.end('Error loading index.html');
    }

    res.writeHead(200); //returning 200
    res.end(data); //printing the data - the index.html content
  });
}

/**
IO event on connection. here is the magic
**/

io.on('connection', function (socket) { //connection event. happends when a connection is initiated
  var clockInterval = setInterval(function(){ //running it every second
  var current_time = getCurrentTime(); //calculating the time 
    socket.emit('clock-event', current_time); //emitting the clock-event through the socket
  },  1000);  
    socket.on("disconnect", function(s) { //when the socket is being closed, destroy the interval
      console.log('user disconnected! resetting interval');
      clearInterval(clockInterval);
  });  
});


/** function for printing the hour. Taken from 
http://www.mcterano.com/blog/%D7%A0%D7%99%D7%A1%D7%95%D7%99-17-%D7%A9%D7%A2%D7%95%D7%9F-%D7%A9%D7%9E%D7%AA%D7%A2%D7%93%D7%9B%D7%9F-%D7%91%D7%96%D7%9E%D7%9F-%D7%90%D7%9E%D7%AA-%D7%91%D7%A2%D7%96%D7%A8%D7%AA-node-js/
**/

function getCurrentTime(){
    var currentDate = new Date();
    var currentHours = addZeroToOneDigit(currentDate.getHours());
    var currentMinutes = addZeroToOneDigit(currentDate.getMinutes());
    var currentSeconds = addZeroToOneDigit(currentDate.getSeconds());
    var currentTime = currentHours + ":" + currentMinutes + ":" + currentSeconds;
    var html = parseHtml(currentTime);
    return html;
}
 
function addZeroToOneDigit(digits){
    var result = ((digits).toString().length === 1) ? "0" + digits : digits;
    return result;
}
 
function parseHtml(currentTime){
    var result = '

'; result += 'השעה כרגע היא: ' + currentTime; result += '.

'; return result; }

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

שימו לב שהפרונט אנד נטען באמצעות index.html שאני טוען עם ה-fs. איך הוא נראה? מאוד פשוט:


<!doctype html>
<html class="no-js" lang="">
    <head>
        <meta charset="utf-8">
        <meta http-equiv="X-UA-Compatible" content="IE=edge">
        <title>שעון</title>
        <meta name="description" content="ניסוי השעון של רן בר-זיק">
        <meta name="viewport" content="width=device-width, initial-scale=1">
    </head>
    <body>
        <!--[if IE]>
            <p>Go away. no IE allowed in here.</p>
        <![endif]-->
        
        <script src="https://cdn.socket.io/socket.io-1.1.0.js"></script>
        <script>
          var socket = io.connect('http://localhost');
          socket.on('clock-event', function (data) {
            document.write(data);
          });
        </script>
    </body>
</html>

socket.io מאפשר לנו עוד כמה דברים – הדבר הכי חשוב זה לשדר מידע מהקליינט. שידור המידע מהשרת או מהקליינט נעשה באמצעות key: value, כך שאפשר לעשות המון שידורים מכל מיני סוגים ולדאוג בקלות לפעולות שונות. העליתי את האימפלמנטציה שלי לגיטהאב. מי שחושב על שיפורים בקוד – קליינט או סרבר מוזמן לדחוף את השינויים שלו 🙂 ינון פרק כבר הכניס שינויים מענינים במיוחד. שווה להסתכל על השינויים שעבר הקוד ולראות איך הוא השתנה בין הדוגמה שהבאתי כאן למה שיש בפועל. אם למישהו יש רעיונות נוספים: זה הזמן!

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

במאמר הבא נדבר על deployment של האפליקציה שכתבתי כאן.

⚠️ תזכורת – המדריכים האלו הם רק טעימה, בספר שלי "ללמוד Node.js בעברית" יש הסברים מלאים ומקיפים על השפה המיועדים ללימוד עצמי. עם תרגילים והסברים. הספר יצא לאור בשיתוף הקריה האקדמית אונו ובתמיכת החברות אלמנטור, ו-Iron source ונערך טכנית על ידי בנג'י גרינבאום (מפתח ליבה של Node.js), גיל פינק ומתכנתים מעולים נוספים. 

פוסטים נוספים שכדאי לקרוא

פתרונות ומאמרים על פיתוח אינטרנט

נגישות טכנית – פודקאסט ומבוא

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

ספריות ומודולים

מציאת PII באמצעות למידת מכונה

כך תגנו על משתמשים שלכם שמעלים מידע אישי רגיש כמו תעודות זהות באמצעות שירות אמאזוני.

רספברי פיי

הרצת גו על רספברי פיי

עולם הרספברי פיי והמייקרים ניתן לתפעול בכל שפה – לא רק פייתון או C – כאן אני מסביר על גו

גלילה לראש העמוד