Building simple chat app with Socket.IO
A lot of websites today have a realtime chat function. Building your own chat library from scratch is difficult and time consuming. Today I will bring you a framework that is not only used for handling chat functions but also many other applications.
この記事の目次
Features
Real-time communication: Enables instant, real-time messaging between clients and servers.
HTTP long-polling fallback: The connection will fall back to HTTP long-polling when it fails to establish websocket connection.
Cross-Browser compatibility: Works across all major browsers and even in environments where WebSockets are not supported.
Automatic reconnection: Attempts to reconnect automatically when the connection is lost.
Multiplexing: Supports multiple independent channels of communication over a single connection.
Namespaces: Allows you to create different communication channels within the same connection.
Rooms: Enables broadcasting messages to all clients in a specific room.
Many programming language implementations: Java, C++, Python, swift, etc.
Applications
Chat applications: Real-time messaging between users.
Online gaming: Real-time interactions between players.
Collaboration tools: Real-time updates in collaborative environments (e.g., document editing).
Live feeds: Real-time data streams for news, sports, or financial updates.
Notification systems: Real-time notifications for various events (e.g., social media notifications).
How it works
Socket.IO is NOT a websocket implementation. It uses websocket as transport to transfer data when possible.
Transports
HTTP long-polling: Use normal HTTP requests to transfer data. Using GET requests for receiving data from the server. POST requests for sending data to the server.
Websocket(WS): This connection provides a bidirectional and low-latency communication channel between the server and the client.
Upgrade mechanism
Socket.IO doesn’t make a websocket connection right away. It makes a GET request first. If the server responds that it is okay to upgrade to websocket, then the connection will be upgraded to websocket. Otherwise using HTTP long-polling.
Event-based communication
With plain websocket connection we send raw data like string or binary data, then server and client will convert these data into usable format. Socket.IO on the other hand, will serialize/deserialize your data automatically. But you can always send raw data as you wish.
For example:
//client side interface MyMessage { userId: number; content: string; }; const message: MyMessage = { userId: 10, content: "Hello" }; socket.emit("new-message", message); //server side io.on("new-message", (data: MyMessage) => { console.log(data.userId); });
As you can see, the server doesn’t need extra steps to transform data from the client. This makes development more convenient.
Install
Socket.IO library can be installed by using node.js package managers like npm or yarn . Frontend(FE) will use the client library(socket.io-client) and Backend(BE) will use the server library(socket.io).
npm install -S socket.io npm install -S socket.io-client
or
yarn add socket.io yarn add socket.io-client
Install bootstrap
This is optional. I want a better visualization so I use a library for UI.
npm install -S react-bootstrap bootstrap
or
yarn add react-bootstrap bootstrap
Then add CSS to your _app file.
import "bootstrap/dist/css/bootstrap.min.css";
Creating a chat application
I will create two folders, one for FE and one for BE.
Two new added files are index.js and chat.tsx. If you don’t have package.json you can create it manually or by using the command below.
npm init
or
yarn init
After creating project folders and files, you can copy the code below and paste it.
index.js
const server = require("http").createServer(); const io = require("socket.io")(server, { cors: { origin: "http://localhost:3000",//allow FE origin methods: ["GET", "POST"] } }); const CHAT_MESSAGE_EVENT = "chat_message"; io.on("connection", (socket) => { socket.on(CHAT_MESSAGE_EVENT, (msg) => { //broadcast this message to all connected users io.emit(CHAT_MESSAGE_EVENT, msg); }); }); server.listen(3001, () => { console.log("server running at http://localhost:3001"); });
chat.tsx
import Head from "next/head"; import { useEffect, useState } from "react"; import { Button, Col, Container, Row } from "react-bootstrap"; import Form from "react-bootstrap/Form"; import { io } from 'socket.io-client'; const socket = io("http://localhost:3001", { autoConnect: false }); const CHAT_MESSAGE_EVENT = "chat_message"; export default function Chat() { const [message, setMessage] = useState(""); const [userName, setUserName] = useState("user01"); const [messageList, setMessageList] = useState<string[]>([]); const onSendMessage = () => { if (!socket.connected || !message || !userName) { return; } socket.emit(CHAT_MESSAGE_EVENT, `${userName}:${message}`); setMessage(""); }; useEffect(() => { socket.connect(); const onChatMessage = (data: string) => { setMessageList((prev) => [...prev, data]); }; socket.on(CHAT_MESSAGE_EVENT, onChatMessage); return () => { socket.off(CHAT_MESSAGE_EVENT, onChatMessage); }; }, []); return ( <> <Head> <title>Socket.IO Chat</title> <meta name={"description"} content={"chat page"} /> <meta name={"viewport"} content={"width=device-width, initial-scale=1"} /> <link rel={"icon"} href={"/favicon.ico"} /> </Head> <Container className={"vh-100 overflow-hidden d-flex flex-column justify-content-between"}> <Container className={"flex-grow-1 overflow-auto pt-2"} fluid> {messageList.map((v, i) => ( <Row key={i} xs={12} style={{ whiteSpace: "pre-line" }}>{v}</Row> ))} </Container> <Row className={"py-2"}> <Col xs={12} md={8}> <Form.Control value={message} onChange={(e) => setMessage(e.target.value)} as={"textarea"} rows={4} placeholder={"message"} /> </Col> <Col xs={12} md={4}> <Form.Label>User name:</Form.Label> <Form.Control value={userName} onChange={(e) => setUserName(e.target.value)} placeholder={"user name"} /> <Button className={"mt-2"} onClick={onSendMessage}>Send</Button> </Col> </Row> </Container> </> ); }
Explanation
FE: We have two inputs for inputting messages, user name and message list. user name and message will be sent to BE by clicking the send button. To start FE, open your terminal in the FE folder and run the command below.
npm run dev
or
yarn run dev
Your chat page url will be http://localhost:3000/chat
BE: It will broadcast your message to all connected users. To start BE, open your terminal in the BE folder and run the command below.
node index.js
Result
I opened two windows to test. As you can see, the user name is included in the message so we can know who sent it.
Summary
Socket.IO is a good framework for realtime communication. It supports many programming languages and is easy to integrate into your application. So let’s give it a try!
References:
Socket.IO
Next.js by Vercel – The React Framework (nextjs.org)
React Bootstrap | React Bootstrap (react-bootstrap.netlify.app)
カテゴリー: