I am trying to make a small online browser game with websockets and javascript, but websockets close after 60 seconds with error code 1006 and no reason (onerror is not called), although I have a ping-pong requests every 5 seconds. I was able to replicate it with this code:
// server.js
const ws = require("ws")
const { createServer } = require("http")
const server = new ws.Server({ noServer: true })
createServer((req, res) => {
server.handleUpgrade(req, req.socket, Buffer.alloc(0), (socket, req) => {
socket.on("message", (message) => {
if (message == "Ping")
socket.send("Pong")
console.log(message.toString())
})
socket.on("close", () => {
console.log("closed")
})
socket.on("error", (err) => {
throw err;
})
})
}).listen(8000, "127.0.0.1")
<!--- index.html --->
<!DOCTYPE html>
<html>
<body>
<script>
var ws = new WebSocket("ws://127.0.0.1:8000");
ws.onopen = (ev) => {
ws.send("Hello, Server!");
ws.onmessage = (ev) => {
console.log(ev.data);
}
ws.onclose = (ev) => {
console.log(`Closed ${ev.code} : ${ev.reason}`);
}
ws.onerror = (err) => {
console.log(err);
}
(async () => {
function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
while (ws.readyState == 1) {
ws.send("Ping");
await sleep(5000);
}
})();
}
</script>
</body>
</html>
I tried to lower the ping-pong sleep, but it doesn't seem to do anything, still closes after exactly 60 seconds. It errors in Chrome, Firefox, Opera and Edge browsers.
I can't really say why the server fails as it does, I don't know the inner workings of nodes http
- I suspect because of the way it's done, the http
code believes there's no data coming through the socket, so eventually closes it as inactive
Alternative 1:
A little more complex, but works fine - using this method, you can actually have multiple websocket implementations on the one server (see examples Multiple servers sharing a single HTTP/S server as documented on ws
npm page
const wss1 = new ws.Server({ noServer: true });
wss1.on("connection", (socket) => {
console.log("wss1 connection");
socket.on("message", (message) => {
if (message == "Ping") {
socket.send("Pong");
}
console.log(message.toString());
});
socket.on("close", () => {
console.log("closed");
});
});
const server = createServer();
server.on("upgrade", (req, socket, head) => {
wss1.handleUpgrade(req, socket, head, (ws) => {
wss1.emit("connection", ws, req);
});
});
server.listen(8000, "127.0.0.1");
Alternative 2:
Very simple code
const server = createServer();
const wss = new ws.Server({ server });
wss.on("connection", (socket) => {
console.log("wsServer connection");
socket.on("message", (message) => {
if (message == "Ping") {
socket.send("Pong");
}
console.log(message.toString());
});
socket.on("close", () => {
console.log("closed");
});
});
server.listen(8000, "127.0.0.1");