Difference between revisions of "Socket.IO"

From CSE330 Wiki
Jump to navigationJump to search
Line 1: Line 1:
−
AJAX is useful when one-way communication is satisfactory for your web application. However, what happens when you need two-way communication, like a chat client or multiplayer game? AJAX isn't the tool for the job. This is where '''Socket.IO''' comes in.
+
AJAX is useful when one-way communication is satisfactory for your web application. However, what happens when you need true two-way communication, such as a chat client, collaborative app, or multiplayer game? AJAX is not the right tool for that job. This is where '''Socket.IO''' comes in.
  
−
Built to work natively with Node.JS, Socket.IO enables asynchronous, two-way communication between the server and the client. This means that the server can send messages to the client without the client having to ask first, as is the case with AJAX. As you learn Socket.IO, Non-Blocking I/O will become your best friend!
+
Socket.IO enables low-latency, bidirectional, event-based communication between the server and the client. Unlike AJAX polling, the server can send messages to the client without the client requesting them first. As you learn Socket.IO, the concept of non-blocking I/O in Node.js will become very important.
  
 
== Installing Socket.IO ==
 
== Installing Socket.IO ==
  
−
Before you install Socket.IO, you need to install [[Node.JS]] and NPM, which is often installed automatically when you install Node.JS.
+
Before installing Socket.IO, you should already have [[Node.JS]] installed and be comfortable with the project setup used in the previous section (npm init, ES Modules, etc.).
  
−
The NPM package manager is different from many of the package managers we've used in that you need to install remote packages for every project in which you use them.  This means that you need to '''cd''' to the working directory in which you want to keep your Node.JS JavaScript file, ''and then'' run the following command:
+
If you are starting a new project:
  
 
<source lang="bash">
 
<source lang="bash">
−
$ npm install socket.io --save
+
$ mkdir chat
 +
$ cd chat
 +
$ npm init -y
 
</source>
 
</source>
  
−
'''Note:''' If you pass the ''-g'' to ''npm install'', then the package will be installed "globally" on your instance, so all Node.JS projects will be able to use it.
+
'''Important:''' Ensure your <code>package.json</code> contains:
 +
 
 +
<source lang="json">
 +
"type": "module"
 +
</source>
 +
 
 +
This enables modern ES Module syntax (<code>import</code>).
 +
 
 +
Now install Socket.IO:
 +
 
 +
<source lang="bash">
 +
$ npm install socket.io
 +
</source>
 +
 
 +
Socket.IO is installed locally inside <code>node_modules</code> and recorded automatically in <code>package.json</code>.
  
 
== Messaging ==
 
== Messaging ==
  
−
Socket.IO works by having clients send messages to the server and the server send messages to clients. For example, consider the code:
+
Socket.IO uses an event-based model. Clients and servers send named events to each other.
 +
 
 +
Example:
  
 
<source lang="javascript">
 
<source lang="javascript">
−
// Computer A:
+
// Sender (client or server)
−
socket.emit("info", {
+
socket.emit("info", { hello: "world" });
−
"hello": "world"
 
−
});
 
  
−
// Computer B:
+
// Receiver (client or server)
−
socket.on("info", function (data) {
+
socket.on("info", (data) => {
−
console.log(data.hello);
+
  console.log(data.hello);
 
});
 
});
 
</source>
 
</source>
  
−
Computer A could be ''either the client or the server'', and Computer B would be the other.  When '''socket.emit(name, data)''' is called on either end, the callback function in '''socket.on''' that listens for the message named ''name'' is called with the ''data'' from '''socket.emit'''.
+
When <code>socket.emit(name, data)</code> is called, any listener registered with <code>socket.on(name, ...)</code> will execute and receive the data.
 +
 
 +
Either side (client or server) can emit or receive events.
  
 
== A First Socket.IO Application: Chat Server and Client ==
 
== A First Socket.IO Application: Chat Server and Client ==
  
−
Building a chat client is surprising simple using Socket.IO and Node.JS, and it gives great insight into the workings of Socket.IO. Take the time to understand how this example works, and ask questions; if you understand this, the group portion will be easy!
+
Building a simple chat application demonstrates the fundamentals of Socket.IO and real-time communication. Understanding this example will make later group features (rooms, private messaging, etc.) much easier.
  
 
=== The Chat Server ===
 
=== The Chat Server ===
  
−
You can make a file called ''chat-server.js'' with the following code:
+
Create a file named <code>chat-server.js</code>:
  
 
<source lang="javascript">
 
<source lang="javascript">
−
// Require the packages we will use:
+
import { createServer } from "node:http";
−
const http = require("http"),
+
import { readFile } from "node:fs/promises";
−
    fs = require("fs");
+
import { Server } from "socket.io";
  
 
const port = 3456;
 
const port = 3456;
 
const file = "client.html";
 
const file = "client.html";
−
// Listen for HTTP connections.  This is essentially a miniature static file server that only serves our one file, client.html, on port 3456:
 
−
const server = http.createServer(function (req, res) {
 
−
    // This callback runs when a new connection is made to our HTTP server.
 
−
 
−
    fs.readFile(file, function (err, data) {
 
−
        // This callback runs when the client.html file has been read from the filesystem.
 
  
−
        if (err) return res.writeHead(500);
+
// Minimal HTTP server that serves client.html
−
        res.writeHead(200);
+
const httpServer = createServer(async (req, res) => {
−
        res.end(data);
+
  try {
−
     });
+
    const data = await readFile(file);
 +
    res.writeHead(200, { "Content-Type": "text/html" });
 +
    res.end(data);
 +
  } catch {
 +
     res.writeHead(500, { "Content-Type": "text/plain" });
 +
    res.end("Could not load client.html");
 +
  }
 
});
 
});
−
server.listen(port);
 
  
−
// Import Socket.IO and pass our HTTP server object to it.
+
// Attach Socket.IO to the HTTP server
−
const socketio = require("socket.io")(http, {
+
const io = new Server(httpServer);
−
    wsEngine: 'ws'
 
−
});
 
  
−
// Attach our Socket.IO server to our HTTP server to listen
+
io.on("connection", (socket) => {
−
const io = socketio.listen(server);
+
  console.log("New connection:", socket.id);
−
io.sockets.on("connection", function (socket) {
 
−
    // This callback runs when a new Socket.IO connection is established.
 
  
−
    socket.on('message_to_server', function (data) {
+
  socket.on("message_to_server", (data) => {
−
        // This callback runs when the server receives a new message from the client.
+
    console.log("message:", data.message);
  
−
        console.log("message: " + data["message"]); // log it to the Node.JS output
+
    // Broadcast message to all connected clients
−
        io.sockets.emit("message_to_client", { message: data["message"] }) // broadcast the message to other users
+
    io.emit("message_to_client", { message: data.message });
−
    });
+
  });
 
});
 
});
  
 +
httpServer.listen(port, () => {
 +
  console.log(`Server running at http://localhost:${port}/`);
 +
});
 
</source>
 
</source>
  
−
The above code makes a simple HTTP server that responds to all connections with the contents of the file "client.html", which we will make in the next step.  We tell Socket.IO to listen for "message" events, and when it hears one, it should emit a new event called "someone said" back to the connected clients.
+
What this server does:
 +
 
 +
* Serves <code>client.html</code>
 +
* Accepts Socket.IO connections
 +
* Listens for <code>message_to_server</code> events
 +
* Broadcasts messages to all clients
  
 
=== The Chat Client ===
 
=== The Chat Client ===
  
−
Here is a front-end client that could work with our server, in ''client.html'':
+
Create <code>client.html</code>:
  
 
<source lang="html4strict">
 
<source lang="html4strict">
−
 
 
<!DOCTYPE html>
 
<!DOCTYPE html>
 
<html>
 
<html>
−
  <head>
+
<head>
−
      <script src="/socket.io/socket.io.js"></script>
+
<meta charset="utf-8">
−
      <script>
+
<title>Socket.IO Chat</title>
 +
</head>
  
−
      var socketio = io.connect();
+
<body>
−
      socketio.on("message_to_client",function(data) {
 
−
        //Append an HR thematic break and the escaped HTML of the new message
 
−
        document.getElementById("chatlog").appendChild(document.createElement("hr"));
 
−
        document.getElementById("chatlog").appendChild(document.createTextNode(data['message']));
 
−
      });
 
  
−
      function sendMessage(){
+
<input type="text" id="message_input">
−
        var msg = document.getElementById("message_input").value;
+
<button id="send_btn">Send</button>
−
        socketio.emit("message_to_server", {message:msg});
+
<div id="chatlog"></div>
−
      }
 
  
−
      </script>
+
<script src="/socket.io/socket.io.js"></script>
−
  </head>
+
<script>
−
  <body>
+
const socket = io();
−
      <input type=text" id="message_input"/>
+
 
−
      <button onclick="sendMessage()">send</button>
+
socket.on("message_to_client", (data) => {
−
      <div id="chatlog"></div>
+
  const chatlog = document.getElementById("chatlog");
−
  </body>
+
  chatlog.appendChild(document.createElement("hr"));
 +
  chatlog.appendChild(document.createTextNode(data.message));
 +
});
 +
 
 +
function sendMessage() {
 +
  const input = document.getElementById("message_input");
 +
  const msg = input.value;
 +
  socket.emit("message_to_server", { message: msg });
 +
  input.value = "";
 +
}
 +
 
 +
document.getElementById("send_btn").addEventListener("click", sendMessage);
 +
</script>
 +
 
 +
</body>
 
</html>
 
</html>
 +
</source>
 +
 +
This example sends a JavaScript object as event data, but any datatype may be used.
 +
 +
=== Running the Chat Server ===
  
 +
Start the server:
 +
 +
<source lang="bash">
 +
$ node chat-server.js
 
</source>
 
</source>
  
−
'''Note:''' This example passes strings as the event data, but you can pass any JavaScript datatype, including object literals.
+
Open:
  
−
To see this in action, save these two files in the same directory, cd over to the directory, and start the server:
+
http://localhost:3456/
  
−
<source lang="bash">$ node chat-server.js</source>
+
Open the page in two browser windows. Messages typed in one window appear in the other — a simple real-time chat system.
 +
 
 +
If running on EC2, ensure port 3456 is open.
 +
 
 +
== Broadcasting Behavior ==
 +
 
 +
Socket.IO supports several broadcast patterns:
 +
 
 +
* <code>io.emit(...)</code> → send to all clients
 +
* <code>socket.broadcast.emit(...)</code> → send to all except sender
 +
* <code>io.to(room).emit(...)</code> → send to a specific room
 +
 
 +
== Rooms (Concept) ==
 +
 
 +
Rooms allow grouping sockets so messages only go to certain users (e.g., chat rooms, game sessions).
 +
 
 +
Example:
 +
 
 +
<source lang="javascript">
 +
io.on("connection", (socket) => {
 +
 
 +
  socket.on("join_room", (data) => {
 +
    socket.join(data.room);
 +
  });
 +
 
 +
  socket.on("room_message", (data) => {
 +
    io.to(data.room).emit("message_to_client", {
 +
      message: data.message
 +
    });
 +
  });
 +
 
 +
});
 +
</source>
  
−
Fire up your favorite browser and navigate to http://localhost:3456/.  Open the page in two windows. Violà: you have your (very basic) chat client!
+
Rooms are managed on the server and are invisible to clients.
  
 
== Resources ==
 
== Resources ==
  
−
The [http://socket.io/ Socket.IO web site] has concise examples that tell you pretty much all you need to know in order to build a functional Socket.IO web application. A helpful discussion on how to use rooms with Socket.IO can be found [https://socket.io/docs/v4/rooms/ here].
+
* https://socket.io/docs/v4/
 +
* Rooms documentation: https://socket.io/docs/v4/rooms/
  
 
[[Category:Module 7]]
 
[[Category:Module 7]]

Revision as of 13:31, 1 March 2026

AJAX is useful when one-way communication is satisfactory for your web application. However, what happens when you need true two-way communication, such as a chat client, collaborative app, or multiplayer game? AJAX is not the right tool for that job. This is where Socket.IO comes in.

Socket.IO enables low-latency, bidirectional, event-based communication between the server and the client. Unlike AJAX polling, the server can send messages to the client without the client requesting them first. As you learn Socket.IO, the concept of non-blocking I/O in Node.js will become very important.

Installing Socket.IO

Before installing Socket.IO, you should already have Node.JS installed and be comfortable with the project setup used in the previous section (npm init, ES Modules, etc.).

If you are starting a new project:

$ mkdir chat
$ cd chat
$ npm init -y

Important: Ensure your package.json contains:

"type": "module"

This enables modern ES Module syntax (import).

Now install Socket.IO:

$ npm install socket.io

Socket.IO is installed locally inside node_modules and recorded automatically in package.json.

Messaging

Socket.IO uses an event-based model. Clients and servers send named events to each other.

Example:

// Sender (client or server)
socket.emit("info", { hello: "world" });

// Receiver (client or server)
socket.on("info", (data) => {
  console.log(data.hello);
});

When socket.emit(name, data) is called, any listener registered with socket.on(name, ...) will execute and receive the data.

Either side (client or server) can emit or receive events.

A First Socket.IO Application: Chat Server and Client

Building a simple chat application demonstrates the fundamentals of Socket.IO and real-time communication. Understanding this example will make later group features (rooms, private messaging, etc.) much easier.

The Chat Server

Create a file named chat-server.js:

import { createServer } from "node:http";
import { readFile } from "node:fs/promises";
import { Server } from "socket.io";

const port = 3456;
const file = "client.html";

// Minimal HTTP server that serves client.html
const httpServer = createServer(async (req, res) => {
  try {
    const data = await readFile(file);
    res.writeHead(200, { "Content-Type": "text/html" });
    res.end(data);
  } catch {
    res.writeHead(500, { "Content-Type": "text/plain" });
    res.end("Could not load client.html");
  }
});

// Attach Socket.IO to the HTTP server
const io = new Server(httpServer);

io.on("connection", (socket) => {
  console.log("New connection:", socket.id);

  socket.on("message_to_server", (data) => {
    console.log("message:", data.message);

    // Broadcast message to all connected clients
    io.emit("message_to_client", { message: data.message });
  });
});

httpServer.listen(port, () => {
  console.log(`Server running at http://localhost:${port}/`);
});

What this server does:

  • Serves client.html
  • Accepts Socket.IO connections
  • Listens for message_to_server events
  • Broadcasts messages to all clients

The Chat Client

Create client.html:

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Socket.IO Chat</title>
</head>

<body>

<input type="text" id="message_input">
<button id="send_btn">Send</button>
<div id="chatlog"></div>

<script src="/socket.io/socket.io.js"></script>
<script>
const socket = io();

socket.on("message_to_client", (data) => {
  const chatlog = document.getElementById("chatlog");
  chatlog.appendChild(document.createElement("hr"));
  chatlog.appendChild(document.createTextNode(data.message));
});

function sendMessage() {
  const input = document.getElementById("message_input");
  const msg = input.value;
  socket.emit("message_to_server", { message: msg });
  input.value = "";
}

document.getElementById("send_btn").addEventListener("click", sendMessage);
</script>

</body>
</html>

This example sends a JavaScript object as event data, but any datatype may be used.

Running the Chat Server

Start the server:

$ node chat-server.js

Open:

http://localhost:3456/

Open the page in two browser windows. Messages typed in one window appear in the other — a simple real-time chat system.

If running on EC2, ensure port 3456 is open.

Broadcasting Behavior

Socket.IO supports several broadcast patterns:

  • io.emit(...) → send to all clients
  • socket.broadcast.emit(...) → send to all except sender
  • io.to(room).emit(...) → send to a specific room

Rooms (Concept)

Rooms allow grouping sockets so messages only go to certain users (e.g., chat rooms, game sessions).

Example:

io.on("connection", (socket) => {

  socket.on("join_room", (data) => {
    socket.join(data.room);
  });

  socket.on("room_message", (data) => {
    io.to(data.room).emit("message_to_client", {
      message: data.message
    });
  });

});

Rooms are managed on the server and are invisible to clients.

Resources