javascripthtmlwebsockettimeoutws

Javascript WebSocket 1006 error after 60 seconds


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.


Solution

  • 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");