I am using the following logic to verify whether client is connected to websocket or not: Client keeps sending pings at an interval to the server. Server has a timeout which triggers an event on completing. As soon as Client pings server, the server timeout resets. This works fine when one client is connected. But the logic breaks on multiple clients. How can I fix this? As soon as 2nd client connects, Server says client 1 has disconnected and doesn't print anything when either of the 2 disconnect.
This is my server logic:
const WebSocket = require("ws");
const express = require("express");
const app = express();
const server = require("http").createServer(app);
const url = require('url');
const PORT = process.env.PORT || 3000;
const wss = new WebSocket.Server({ server: server });
app.get("/", (req, res) => res.send("Temst."));
var tm;
function ping(client) {
tm = setTimeout(function () {
console.log(`[-] ${client} Disconnected`);
wss.emit("customClose", client);
}, 5000);
}
function pong(client) {
clearInterval(tm);
// console.log("[!] Cleared timeout");
ping(client);
}
wss.on("connection", function connection(ws, req) {
var queryData = url.parse(req.url,true).query;
ping(queryData.id);
console.log(`[+] ${req.socket.remoteAddress} Connected`);
wss.clients.forEach(function each(client) {
if (client.readyState === WebSocket.OPEN) {
message = {
type: "alert",
msg: `${queryData.id} has Connected.`,
};
client.send(JSON.stringify(message), { binary: false });
}
});
ws.on("message", function incoming(message) {
if (message == "__ping__") {
console.log(`[!] Ping Receieved from ${req.socket.remoteAddress}`);
pong(queryData.id);
} else {
`[!] Message Receieved from ${req.socket.remoteAddress}`;
wss.clients.forEach(function each(client) {
if (client.readyState === WebSocket.OPEN) {
client.send(msg, { binary: false });
}
});
}
});
});
wss.addListener("customClose", function (m) {
wss.clients.forEach(function each(client) {
if (client.readyState === WebSocket.OPEN) {
message = {
type: "alert",
msg: `${m} has Disconnected.`,
};
client.send(JSON.stringify(message), { binary: false });
}
});
});
server.listen(PORT, () => console.log("Listening on port 3000"));
I think I have solved the problem. After looking at the ws package docs, I tried server side pinging instead of client side. It is working for multiple users for now. Will update if any problems occur.
const WebSocket = require("ws");
const express = require("express");
const app = express();
const server = require("http").createServer(app);
const url = require("url");
const PORT = process.env.PORT || 3000;
const wss = new WebSocket.Server({ server: server });
app.get("/", (req, res) => res.send("Temst."));
var myClients = [];
wss.on("connection", function connection(ws, req) {
var queryData = url.parse(req.url, true).query;
myClients.push({
id: queryData.id,
wsoc: ws,
isAlive: true,
});
console.log(`[+] ${req.socket.remoteAddress} Connected`);
wss.clients.forEach(function each(client) {
if (client.readyState === WebSocket.OPEN) {
message = {
type: "alert",
msg: `${queryData.id} has Connected.`,
};
client.send(JSON.stringify(message), { binary: false });
}
});
ws.on("pong", () => {
let x = myClients.find((o) => o.wsoc === ws);
x.isAlive = true;
});
ws.on("message", function incoming(message) {
console.log(`[!] Message Receieved from ${req.socket.remoteAddress}`);
msg = JSON.parse(message);
console.log(queryData);
msg = { ...msg, time: new Date().toISOString() };
wss.clients.forEach(function each(client) {
if (client.readyState === WebSocket.OPEN) {
client.send(JSON.stringify(msg), { binary: false });
}
});
});
});
wss.addListener("customClose", function (m) {
wss.clients.forEach(function each(client) {
if (client.readyState === WebSocket.OPEN) {
message = {
type: "alert",
msg: `${m} has Disconnected.`,
};
client.send(JSON.stringify(message), { binary: false });
}
});
});
const interval = setInterval(function ping() {
myClients.forEach((clnt, index) => {
if (clnt.isAlive === false) {
console.log("[-]", clnt.id, "has Disconnected.");
wss.emit("customClose", clnt.id);
clnt.wsoc.terminate();
myClients.splice(index, 1);
}
clnt.isAlive = false;
clnt.wsoc.ping();
});
}, 5000);
server.listen(PORT, () => console.log("Listening on port 3000"));