Module5-SocketIO-Test

From CSE330 Wiki
Revision as of 14:34, 24 February 2026 by Todd (talk | contribs) (Created page with "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, collaborativ...")
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to navigationJump to search

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, collaborative whiteboard, live dashboard, or multiplayer game? AJAX isn't the tool for the job. This is where Socket.IO comes in.

Socket.IO is a library that enables low-latency, bidirectional, event-based communication between the server and the client. One key advantage is that the server can send messages to the client without the client having to ask first (as is the case with traditional AJAX polling). As you learn Socket.IO, the Node.js idea of non-blocking I/O will become your best friend! :contentReference[oaicite:0]{index=0}

Installing Socket.IO

Before you install Socket.IO, you need to install Node.JS (which includes npm). We strongly recommend using the current Node LTS.

Socket.IO is installed per-project (locally). This means you should cd to the project folder where your server code will live, then run:

$ npm init -y
$ npm install socket.io

:contentReference[oaicite:1]{index=1}

Note on "global" installs: If you pass -g to npm install, the package is installed globally. For course projects, avoid global installs unless you are very confident you understand why you need them. Local installs make your project portable and reproducible.

A note about modern Node (ES Modules)

Modern Node.js uses ES Modules (import/export) instead of the older require() syntax.

To enable ES Modules, add this line to your package.json:

{
  "type": "module"
}

If you do not want to use ES Modules, you can still use CommonJS (require), but all examples below use modern ESM syntax.

Messaging

Socket.IO works by having clients and servers send named events to each other.

For example:

// Computer A:
socket.emit("info", {
  hello: "world"
});

// Computer B:
socket.on("info", (data) => {
  console.log(data.hello);
});

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, any listeners registered with socket.on(name, ...) on the other end will run and receive the data.

This event-based model is inspired by Node's EventEmitter style: emit events on one side, listen on the other. :contentReference[oaicite:2]{index=2}

A First Socket.IO Application: Chat Server and Client

Building a chat client is surprisingly simple using Socket.IO and Node.js, and it gives great insight into how Socket.IO works. Take the time to understand how this example works. If you understand this, adding more features (usernames, rooms, typing indicators, etc.) becomes 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";

/*
  Mini static server:
  - serves ONLY client.html for any request
  - Socket.IO also exposes a client bundle at /socket.io/socket.io.js
*/
const httpServer = createServer(async (req, res) => {
  try {
    const data = await readFile(file);
    res.writeHead(200, { "Content-Type": "text/html" });
    res.end(data);
  } catch (err) {
    res.writeHead(500, { "Content-Type": "text/plain" });
    res.end("Server error: could not read client.html");
  }
});

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

io.on("connection", (socket) => {
  // Runs when a new Socket.IO connection is established
  console.log("New connection:", socket.id);

  socket.on("message_to_server", (data) => {
    // Runs when the server receives a new message from a client
    console.log("message:", data.message);

    // Send to everyone (including the sender):
    io.emit("message_to_client", { message: data.message });

    // If you wanted: send to everyone EXCEPT the sender:
    // socket.broadcast.emit("message_to_client", { message: data.message });
  });
});

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

What this server does:

  • Creates a basic HTTP server that serves a single file, client.html.
  • Attaches a Socket.IO server to that HTTP server.
  • Listens for a client event called message_to_server.
  • When a message arrives, it broadcasts a message_to_client event to connected clients.

Important note: By default, the Socket.IO server exposes a browser client bundle at /socket.io/socket.io.js which we use from the HTML page. :contentReference[oaicite:3]{index=3}

The Chat Client

Create client.html:

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />
    <title>Socket.IO Chat Demo</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(); // connects back to the same host/port

      socket.on("message_to_client", (data) => {
        // Append an HR and then the message as text (safe against XSS)
        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 = "";
        input.focus();
      }

      document.getElementById("send_btn").addEventListener("click", sendMessage);

      // Optional: press Enter to send
      document.getElementById("message_input").addEventListener("keydown", (e) => {
        if (e.key === "Enter") sendMessage();
      });
    </script>
  </body>
</html>

Note: This example sends an object ({message: ...}) as the event data, but you can send any JavaScript datatype, including numbers, strings, arrays, and object literals.

Also notice that we display messages using createTextNode(), which treats content as plain text (helpful to avoid XSS when printing user-generated input).

Running the Example

Save chat-server.js and client.html in the same directory, then:

$ node chat-server.js

Open your browser to:

http://localhost:3456/

Open the page in two windows (or two different browsers). Now type messages — you have a (very basic) chat client!

Broadcasting: "everyone" vs "everyone else"

Socket.IO gives you multiple ways to send events:

  • io.emit(...) sends to everyone connected (including the sender).
  • socket.broadcast.emit(...) sends to everyone except the sender.
  • io.to(room).emit(...) sends only to sockets in a specific room (see below).

Broadcasting is a server-side feature. :contentReference[oaicite:4]{index=4}

Rooms (and why you care)

Rooms are a server-only concept that let you group sockets together so you can broadcast to a subset of clients (for example: one chat room per group). :contentReference[oaicite:5]{index=5}

Basic idea:

  • A socket can join and leave rooms.
  • You can emit to everyone in a room.

Example (server-side):

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

  socket.on("room_message", (data) => {
    // send only to people in that room
    io.to(data.room).emit("message_to_client", { message: data.message });
  });
});

Rooms make it much easier to build:

  • group chats
  • team-based games
  • collaborative apps with separate workspaces

Resources