-
Notifications
You must be signed in to change notification settings - Fork 11
Home
Create and explain.
Chatcus is a real-time chat. In order to archive that, Chatcus uses:
- Socket.IO for the communication between the browser and the server
- Reactjs to handle all the information coming from the server and present it in a certain way to the user
Like we said before, we are going to use Socket.IO for the communcation. SocketIO uses WebSocket, a communication protocol which provides a full-duplex and low-latency channel between the browser and the server.
Let's see how we manage this concepts in our code.
// File: /server/src/index.js
const express = require("express");
const socketio = require("socket.io");
const http = require("http");
const app = express();
const server = http.createServer(app);
const io = socketio(server);
-
We import import express and Socket.IO in our app.
-
We import http, but wait here. Why? 🤷♂️
A WebSocket server is nothing more than an application listening on any port of a TCP server that follows a specific protocol. With that in mind, if we are using Socket.IO, which uses WebSocket, why do we still need HTTP protocol?
Everything that we need to understand we can read it in Writing WebSocket servers, documentation provided by Mozilla, but I am going to explain it in a few words.
First, the server must listen for incoming socket connections using a standard TCP socket. After this, comes the handshake, where there is all the details of the connection what are we negotiating. We need all this details cause the server must understand everything the client asks for, otherwise security issues can occur.
However, even though you are building a server, a client still has to start the WebSocket handshake process by contacting the server and requesting a WebSocket connection. So, you must know how to interpret the client's request. The client will send a pretty standard HTTP request with headers that looks like this:
GET /chat HTTP/1.1 Host: example.com:8000 Upgrade: websocket Connection: Upgrade Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ== Sec-WebSocket-Version: 13
When the server receives the handshake request, it should send back a special response that indicates that the protocol will be changing from HTTP to WebSocket.
-
We create an express app.
-
With that express app, we are going to create our http server.
-
Now we can initialize a new instance of
socket.io
by passing theserver
(the HTTP server) object.
Next, we must be listenning in some port using our HTTP server:
// File: /server/src/index.js
const PORT = 5000;
server.listen(PORT, () => {
console.log(`Server has started on port ${PORT}}`);
});
Now, we must be listening for incoming sockets connections. With io.on()
method we listen for the "connection"
event and then we log it to the console.
// File: /server/src/index.js
io.on("connection", (socket) => {
console.log("new user connected!")
socket.on("disconnect", () => {
console.log("a user has left")
});
});
In the client that we have:
// File: /client/src/Components/Chat.js
import { io } from "socket.io-client";
const ENDPOINT = "localhost:5000";
let socket = io(ENDPOINT, {
transports: ["websocket"],
});
-
We import Socket.
-
We define an
ENDPOINT
where occur the packets exchanged between the client and the server -
We create a new Socket instance. Why do you pass those parameters to it?
io(url, options)
and returnsSocket
We learned from the Pull Request 3 that we can have troubles connection issues if:
- The client is not compatible with the version of the server.
JS Client version Socket.IO server version 1.x 2.x 3.x 4.x 1.x YES NO NO NO 2.x NO YES YES YES 3.x NO NO YES YES 4.x NO NO YES YES - You are trying to reach a plain WebSocket server. Although Socket.IO indeed uses WebSocket as a transport when possible, it adds additional metadata to each packet. That is why a WebSocket client will not be able to successfully connect to a Socket.IO server, and a Socket.IO client will not be able to connect to a plain WebSocket server either.
Until now we are only able to establish a connection between client and server, but we have not sent any message yet. Let's see how we can send message.
The main idea behind Socket.IO is that you can send and receive any events you want, with any data you want. That is what we can do with socket.emit()
, both client and server side.
We can see it better with the example:
// File: /client/src/Components/Chat.js (Client)
socket.emit("join", { name, room }, (error) => {
if (error) {
alert(error);
}
});
return () => {
socket.emit("disconnect");
socket.off();
};
// File: /server/src/index.js (Server)
io.on("connection", (socket) => {
socket.on("join", ({ name, room }, callback) => {
const { error, user } = addUser({ id: socket.id, name, room });
if (error) {
return callback(error);
}
socket.join(user.room);
socket.emit("message", {
user: "admin",
text: `${user.name} welcome to the room ${user.room}`,
});
socket.broadcast
.to(user.room)
.emit("message", { user: "admin", text: `${user.name} has joined!` });
callback();
...
});
Client
-
We emit an event.
With
socket.emit(eventName, ...args, ack)
we emit that event passing to it a event name called"join"
. We are passing parameters as well and a callback function in case of error. More info here. -
In order to notify the server when we are leaving the site, we inform sending him emitting a
"disconnected"
event.
Server
-
We receive the event
"join"
from the client, and all the parameters that comes with it. -
We can handle those parameters for example welcoming the new user in the room.
-
Before it, we can see how we add that user to the room. Wo wo, but wait, what is exactly that?
A room is an arbitrary channel that sockets can
join
andleave
. It can be used to broadcast events to a subset of clients: -
We have the option to send an event to all the users in the room. Socket.IO makes it easy to send events to all the connected clients.
In the previous point, we saw how we can subcribe clients to certain room. Now that concept is useful to simply use
to
orin
(they are the same) and broadcast or emit:io.to("some room").emit("some event");