מדריך Node.js: איך עובדים עם sockets

כיצד יוצרים חיבור מסוג socket או מתחברים אל חיבור שמישהו אחר יצר באמצעות Node.js
Node.js Logo

במאמר הקודם דיברנו על streams, במאמר הזה אנו נדבר על Sockets – או יותר נכון האימפלמנטציה של השרת שאמור לתמוך בזה!

אז מה זה Socket? מדובר בצורת תקשורת שאפשר להפעיל אותה בין שני מחשבים (שני שרתים לצורך העניין) כדי להעביר מיעד. sockets משתמשים ב-TCP על מנת להעביר נתונים. בשונה מבקשות HTTP רגילות, עם sockets אנו יכולים ליצור תקשורת שבה שני הצדדים יכולים לשלוח מידע באופן שווה. בניגוד, למשל, ל-HTTP, שם רק ה-client יכול ליצור בקשות.
למשל, אם אני עובד עם AJAX מול שרת מרוחק, הוא יחזיר לי מידע רק אם אני שולח לו בקשה מפורשת דרך AJAX. אם אני עובד עם Socket, אז ברגע שה-client מתחבר, גם השרת וגם ה-client יכולים ליצור בקשות. כל בקשה ב-Socket מגיע כשהיא הרבה יותר רזה מבקשת HTTP – כלומר חוץ מבקשת החיבור הראשונית אין לנו header.
אם יש לנו שני שרתים שצריכים לקיים תקשורת אחד עם השני – socket היא דרך נהדרת לקיום תקשורת כזו. כאשר התקשורת יכולה להעביר כל סוג נתונים שהוא.

כאשר אנו מדברים על Socket ב-Node.js אנחנו יכולים להיות השרת – זה שיושב ומחכה לבקשות. או הלקוח – זה שיוזם את הבקשה. המודול שיוצר הן את השרת והן את הלקוח הוא net.

יצירת שרת מאוד דומה לשרת http. זה נראה משהו כזה:


var net = require('net');
var server = net.createServer(function(socket) { //'connection' listener
    console.log('server connected');
    socket.on('end', function() {
        console.log('server disconnected');
    });
    socket.write('hello\r\n');
    socket.pipe(socket);
});
server.listen(1311, function() { //'listening' listener
    console.log('server bound');
});

את הקוד לעיל, אגב, שיניתי מעט אבל הוא מתבסס על הדוגמה שיש במתודת createServer בדוקומנטציה.

מה הולך פה? מאוד דומה לשרת רגיל – רק שבמקום request אני מעביר אובייקט socket שדרכו מתבצעת התקשורת. במקרה הזה מדובר בשרת משדר בלבד. הוא כותב רק hello.

איך נבדוק את זה? בדיוק בשביל זה יש לנו את פקודת telnet בחלונות ובלינוקס. נקליד את הפקודה הבאה:


telnet 127.0.0.1 1311

ברגע שנתחבר, נוכל לראות 'hello'.

עוד משהו נחמד שאפשר לראות זה שאני משתמש פה ב- pipe ובמקרה הזה ה-socket הוא ה-writable וה-readable אז זה נראה קצת מצחיק. אבל אנחנו משתמשים בו כדי לבצע streaming.

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


var net = require('net');
var server = net.createServer(function(socket) { //'connection' listener
    console.log('server connected');
    socket.on('end', function() {
        console.log('server disconnected');
    });

    socket.on('data', function(data) {
        console.log('data received:'+data);
        socket.write('data is:'+data);
        socket.pipe(socket);
    });


});
server.listen(1311, function() { //'listening' listener
    console.log('server bound');
});

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



var client = new net.Socket();
client.connect(1311, '127.0.0.1', function() {
    console.log('Connected');

    client.write('Hello, server! Love, Client.');
    client.pipe(client);
});

client.on('data', function(data) {
    console.log('Received: ' + data);
    client.destroy(); // kill client after server's response
});

client.on('close', function() {
    console.log('Connection closed');
});

הדוגמה, אגב, נקלחה במלואה עם שינוי קל (פשוט הוספתי את ה-pipe) מה-Gist הזה.

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

שימו לב שכאשר אנו מדברים על Sockets במאמר הזה – אנחנו לא מדברים על Web Sockets שהוא אימפלמנטציה של Sockets בסביבת דפדפן. למי שלא מכיר את Web Sockets – אני ממליץ בחום רב לקרוא את המאמר על Web Sockets שכתבתי ומסביר איך זה עובד מבחינת הפרונט אנד. למי שכן מכיר: זה לא Web Sockets, אם אנחנו רוצים לממש Web Sockets אז צריך להשתמש בשרת http כדי לממש את הפרוטוקול של ה-Hand Shake של Web Sockets או (מה שכולם עושים) להשתמש במודול חיצוני כדי לעשות את זה.

במאמר הבא אנו נדבר על npm.

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

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

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

יישום של nonce על מנת להגן מפני התקפות injection

בפוסט הקודם הסברתי על hash עם CSP על משאבי inline – שזה נחמד ומעולה אבל פחות ישים בעולם האמיתי שבו בדרך כלל התוכן ה-inline (בין

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

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

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

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

עבודה עם GPT למתכנתים

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

פייתון

קבצי קונפיגורציה בפואטרי

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

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