Search code examples
node.jsexpresswebsocketsocket.iolit-html

Websocket clients override connections of each other


I am trying to implement a Server-Client example with a Nodejs express server and a LitComponent-Client. Communication between server and client works perfectly when running an 1:1 configuration. When starting a second client the transmission of data stops working and only the new client receives data.

All clients run on localhost:3001 - server runs on localhost:3000.

How can I continously send data to multiple clients?

Client

import short from 'short-uuid';
import { io } from 'socket.io-client';

...

constructor() {
    super();

    //Generate app id
    this.app_id = short.generate();
    console.log('# App-ID: ' + this.app_id);

    this.socket = io('ws://localhost:3000', { forceNew: true });

    this.socket.on('connect', () => {
      this.socket.emit('log', 'App-ID: ' + this.app_id);
    });

    this.socket.on('data', message => {
      this.receiveData(message);
    });

    this.socket.on('disconnect', function () {
      console.log('# Socket disconnected');
    });
  }

...

Server

var app = require("express")();
const express = require("express");

var http = require("http").createServer(app);
var io = require("socket.io")(http, {
    cors: {
        origin: "http://localhost:3001",
        methods: ["GET", "POST"],
    },
});

let connectCounter = 0;

let sock;
io.on("connect", (socket) => {
    sock = socket;
    console.log("# " + socket.id + " | ■ App connected");
    connectCounter++;
    console.log("# New connection - now have " + connectCounter);
    socket.on("disconnect", () => {
        connectCounter--;
        console.log("# Lost connection - now have " + connectCounter);
    });
    socket.on("log", (message) => {
        console.log("# " + socket.id + " | " + message);
    });
});

function sendData(msg) {
    sock.emit("data", msg);
}

...

http.listen(3000, () => {
    console.log("# HTTP: listening on *:3000");
});

Solution

  • On the server side you have:

    let sock;
    io.on("connect", (socket) => {
        sock = socket;
        ...
    });
    
    function sendData(msg) {
        sock.emit("data", msg);
    }
    

    Can you see a problem here? Each time a new user connects you set him as a global sock and then you send only to that socket. What you need instead is to keep all sockets in some collection, something like this:

    let sockets = {};
    
    io.on("connect", (socket) => {
        sockets[socket.id] = socket;
        ...
        socket.on("disconnect", () => {
            ...
            delete sockets[socket.id];
        });
    });
    
    function sendData(msg) {
        for (var socket_id in sockets) {
            sockets[socket_id].emit("data", msg);
        }
    }
    

    AFAIK socket.io already does that for you, but I don't remember concrete attributes (it's been a while since I dealt with socket.io), so you'll have to read the api.