5

I am creating a node.js app and running a WebSocket using both a server.js file and a routes.js file. I am trying to use the routes.js file to send a message within a certain page and eventually going to target the socket message to specific websocket clients. For now I am having trouble getting the on("message") function to work.

From the server.js file:

require('./app/routes.js')(app, passport, wss); // load our routes and pass in our app and fully configured passport

wss.on('connection', function connection(ws, req) {
            console.log('Client connected');
            ws.on('message', function incoming(message){
                console.log("Incoming message: %s", message);
            })
            ws.on('close', () => console.log('Client disconnected'));
})
        ;

From the routes.js file:

app.post('/allbooks', function(

req,res)
{
    wss.clients.forEach((client) => {
    var arrayToSend = JSON.stringify([req.body.bookid, [], req.body.userSays]);
        console.log("Printing within routes.js");
        console.log(arrayToSend);
        client.send(arrayToSend);
    });
    res.redirect('/allbooks');    
});

When I send a message, I see "Printing within routes.js" in the log, but I don't see the "Incoming message" part from the server.js part. Why not?

PS Here is the scripts.js file from the page I am running:

var HOST = location.origin.replace(/^http/, 'ws')
  var ws = new WebSocket(HOST);
  ws.onmessage = function (event) {
    eventJSON = JSON.parse(event.data);
      if ($("#"+eventJSON[0]+"-request").length > 0){
        $("#"+eventJSON[0]+"-request").html("Message sent");
      }
    } 
9
  • It looks like you're trying to use a websocket from two server files. Web sockets are for talking from client to server and server to client. Meaning from browser to server and vice versa. Commented Jun 1, 2018 at 21:43
  • I am trying to use it to talk client-server and then analyze that message serverside to broadcast a message server-clients. I can't figure out why the ws.on() in the server.js file is not being triggered. Commented Jun 1, 2018 at 21:46
  • You can use websockets between two different servers if you want but you need to write code to make the client library connect to the server endpoint. What you're doing there is putting an on listener on the same socket you're calling .send on. Commented Jun 1, 2018 at 21:48
  • I don't think I want to use them between two different servers - I want all the websockets to be communicating along the same "socket" if that makes any sense. Commented Jun 1, 2018 at 21:50
  • When you loop through all the clients like you are and then send something you’re sending a message that a connected client socket could listen for. When you attach an on event handler to that same socket you’re listening for messages from that connected client. That handler will not fire for messages you try to send on that same socket. Only from messages sent from the client end of that socket. Commented Jun 1, 2018 at 22:03

1 Answer 1

10

I don't know if this is the package you're using but whatever one you're using will be similar. In the readme it goes over two examples:

Server Example

In the server example they create a web socket server:

const WebSocket = require('ws');

const wss = new WebSocket.Server({ port: 8080 });

wss.on('connection', function connection(ws) {
  ws.on('message', function incoming(message) {
    console.log('received: %s', message);
  });

  ws.send('hello from the server!');
});

What this does is creates the listening socket server. It adds an event listener for message so when a client connects to the server that client can then send messages and that event handler will fire.

After that event listener it sends the string 'hello from the server!'. That send call will NOT fire the above event handler because this send call is happening on the server side of the socket. It is sending a message to be received on the client end of that socket.

Client Example (usually in browser)

const WebSocket = require('ws'); // omit this line if including ws via <script> tag

const ws = new WebSocket('ws://www.host.com/path');

ws.on('open', function open() {
  ws.send('hello from the client!');
});

ws.on('message', function incoming(data) {
  console.log(data);
});

This is a client script that connects to the socket server in the first example. It connects up and the 'connection' event will be raised on the socket server above. The socket server then calls ws.send('hello from the server!'); and our client script here sets up a listener for 'message' so it would fire and print out 'hello from the server!' to the browser console.

This client script also sets up an 'open' event handler which fires after a successful connection to the socket server. So it will fire and send 'hello from the client!' to the server. The server's handler for 'message' will fire and in the server's terminal you will see 'hello from the client!' print out.


In your example you're doing this from the server (your server side routes.js file)

wss.clients.forEach(function each(client) {
  if (client.readyState === WebSocket.OPEN) {
    client.send(data);
  }
});

What you're doing there is iterating over all connected clients that have successfully connected to the socket server and you're sending out a message to each one individually. This will still not fire the server-side on event handler for 'message' you set up on each socket when each one first connected. It will fire the handler on the client-side in the browser.


Edit based on your last comment above:

To do what you want you'd want something like this on the client:

myButton.onClick = function (e) {
  ws.send("Hey everyone! I'm Chev!");
};

Then on the server in the connection handler you'd want to set up a message handler like this:

wss.on('connection', function connection(ws) {
  ws.on('message', function incoming(message) {
    wss.clients.forEach(function each(client) {
      if (client !== ws && client.readyState === WebSocket.OPEN) {
        client.send(message);
      }
    });
  });
});

You can make message be an object instead of a string so you can perform different actions based on properties on that object but for the sake of simplicity I just made the server broadcast any message it receives to the rest of the server.

Notice the if statement checking to make sure we don't re-broadcast the message back to the same client who sent it.

Sign up to request clarification or add additional context in comments.

1 Comment

my console.log("TEXT HERE") is not being called in the ws.on("message") event

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.