Can't receive data from io.emit() - node.js

I am trying to send data to all clients just to test how socket.io works.
I can't seem to get any data back from the server, no matter how I try.
The event is fired, so the data gets to the server side, but it doesn't arrive to the clients.
On the server side, I do this:
io.on('connection', (socket) => {
socket.on('chatMessage', data => {
console.log(data);
io.emit(data);
});
});
The console.log() here works, so its fine until that line.
On the client side I tried to simplify things to see the result like this:
const socket = io.connect('http://localhost:5000');
socket.on('connect', () => {
socket.emit('chatMessage', {a:"fsdfsdfsd"});
});
socket.on('chatMessage', data =>{
console.log(data);
});
The socket.emit() fires, but it doesn't arrive anywhere.
I have never used socket.io before, but I read the docs and it said io.emit() sends the data to all connected clients.
Just in case, I tried with multiple clients connected, but it still doesn't work.

First thing I would recommend is to check if the client is really connecting to the server socket by adding a console.log() inside your on connection block in the server side.
Also, your io.emit(data); in the server side won't work since the first parameter of the emit function should be the event name.

Related

Socket.IO Emit is emitting to all clients

So I'm writing an app in NodeJS, and to preface my question please understand how my setup currently works:
I have Clients who connect via Socket.io to "Server X", and then my "Server X" connects via Socket.io to "Server Y", and they all send data back to each other via Socket.io.
Client <---> Server X <---> Server Y
Clients refer to users and their browsers, and then I have a node app running on both my server x and my server y.
So in the code below on my Server X, if you look at line 4 it works exactly as it should. It emits the message ONLY to the client who requested it.
io.on('connection', function(socket){
// This works just fine.
socket.emit('return_login', 'Test Message');
socket.on('login', function(data){
// This line correctly sends the data to Server Y
server_y.emit('login', data);
});
server_y.on('return_login', function(data){
// This emits to all connected clients???
socket.emit('return_login', data);
});
});
Now my problem is when "Server Y" emits return_login to server x, what I want to happen is for server x to take the value emitted by server y and just send it back to the original client, or web browser. But for some reason that line emits to ALL connected clients.
I have a laptop, this computer and my phone all testing this and every time that emit happens it sends to EVERYONE.
If someone could please help me with this I would greatly appreciate it. If I need to post more code please let me know.
I am not sure about your code. But I usually use room to emit to an user and callback function of socket. This is my solution using callback instead of return_login event
io.on('connection', function(socket){
socket.on('login', function(data, callback){
// Using callback instead of return_login event
server_y.emit('login', data, function(responseData){
// put this socket to room as name = user_id
socket.join(responseData.user_id);
// return result by callback
callback(responseData)
});
});
});
// emit to exactly user_id with return_login event if you want
io.to(user_id).emit('return_login', {key: 'ok'})
It is sending to all clients because you have installed a separate listener for each socket for the return_login message. So, when one client logs in and the return_login message is sent back to your server, you have a separate listener for every single socket that sees that message and forwards it to that socket. In this way, it gets sent to every connected socket.
One way to fix that is to make sure that the return_login message is only sent to the socket that it belongs to. If you can send a socket.id with that message and have that server echo that id back as part of the response, then you can check that when you receive the message to make sure you only send it to the socket that it belongs to.
This is one of the issues with a pure message-based system. You are trying to do a request/response where only the requester sees the response, but socket.io isn't a request/response system. A response is sent to all listeners of that particular message and since you have a listener for that message for every single socket that is connected, every single socket is seeing it and then forwarding it on to it's client.
So, with a corresponding modification to the other server to echo back the id value, you could do this:
io.on('connection', function(socket){
// This works just fine.
socket.emit('return_login', 'Test Message');
socket.on('login', function(data){
// add our id so we can identify our response back
data.id = socket.id;
server_y.emit('login', data);
});
let fn = function(data) {
// check to see if this message is destined for this socket
if (data.id === socket.id) {
// make data copy with id value removed so
// we don't send that to the client
let tempData = Object.assign({}, data);
tempData.delete(id);
socket.emit('return_login', tempData);
// we're done with this listener so remove it
server_y.removeListener('return_login', fn);
}
});
server_y.on('return_login', fn);
});
It might be tempting to just remove your listener for the return_login message after you receive it, but that causes a race condition if two clients happen to both be in the process of logging in at the same time and thus both have listeners at the same time, then the first message would be received by both listeners.

How can a new client get socket data if it hasn't been emitted since connected

I have googled for hours but cannot seem to find an answer. I have clients emitting and listening to sockets, some change very frequent while others might only change every few minutes. My question is when a new client connects (or connected client refreshes) how does it get the data from those that only change every few minutes before the server emits it?
Client code
var socket = io.connect();
socket.on('frequent', function(data){
$frequent.text(data);
});
socket.on('occasional', function(data){
$occasional.text(data);
});
Server code (Theoretically. The emits work fine are are not the problem)
io.emit('frequent', data);
io.emit('occasional', data);
When a client connects to the server, the server can immediately send the current state of the data:
io.on('connection', function(socket) {
socket.emit("status", currentData);
});
This way, the client gets the current status immediately and doesn't have to wait for the next change.

Verify that the client has received the message from the server

In a chat service that I'm building, I need to send messages directly from the server.
I have found no solution, there is an example in the documentation:
// SERVER
io.sockets.on('connection', function (socket) {
socket.on('ferret', function (name, fn) {
fn('woot');
});
});
// CLIENT
socket.on('connect', function () { // TIP: you can avoid listening on `connect` and listen on events directly too!
socket.emit('ferret', 'tobi', function (data) {
console.log(data); // data will be 'woot'
});
});
but does the opposite of what I need!
I need to do the emit from the server and receive a confirmation of receipt from the client!
Is there a way to do this?
there is no guarantee as the connection can be killed before the servers message reaches the client. thus there is also no event on the server like "clientGotMessage". if a message MUST reach the user there is no other way than to tell the server that you received the message on the client.
You can do this 'easy' by sending a number down. client and server keep track of that number. each time the server sends, it counts up, each time the client receives, it counts up. When the client sends something, it sends the number, so the server will see if the client has everything. If the client missed a message, the next message will have a number that the client wont accept and request the lost message from the server.

emitting data via socket on browser close /window close

I need to send data to nodejs server via socket.io when the user closes the browser tab .
I tried doing :
var data={};
window.onbeforeunload = function() {
// i have a object to be sent
data.data1='abcd';
data.data2=1234;
socket.emit("senddata",data);
}
This code works when the user navigates around clicking links on the site but doesnot work when the user closes the browser tab
I also tried configuring the socket io on server side as below .. thinking the error may be due to socket connection being closed before emitting data:
var io = require('socket.io').listen(app.listen(port));
io.configure(function () {
io.set('close timeout',12000);
});
It also didnt work most of the time.
I also tried this on client side:
var socket = require('socket.io').listen(80, {
"sync disconnect on unload":false
});
It also did not work
I had tried receiving data like this
var io = require('socket.io').listen(app.listen(port));
io.sockets.on('connection', function (socket) {
socket.on('senddata', function (data) {
// data processing
});
});
please ..help me with this problem..thanks in advance..
When user connects - register on server side the time it happened.
Socket.IO has heart beating and pinging functionality. So just subscribe to disconnect event on server side and once it happens - means client disconnected - and you have on server time when client had connection. So that way you have timespan of client session.
Do not trust client to tell you any time or important data, as client can simply 'lie' - which leads to hacks/cheats/bugs on your server-side.
There is no reliable way to send data just before disconnect from client-side at all. There is nothing in Socket.IO for that, nor in just one of transports (WebSockets). As well as there is too many different scenarios of disconnection (power off, force close, ethernet cable out, wifi lose, etc).

Socket.IO is not triggering the connect event

I'm trying to setup a Socket.IO server, and right now, connecting doesn't seem to be working the way it does in the Wiki. I'm connecting to a server using the namespace /client, and I'm successfully seeing the connection made in the debug log, but the connection message is never display (and the other contents are never getting attached).
Server-side
var clients = io
.of('/client')
.on('connect', function (socket) {
// This is never getting run
console.log('Client connected');
});
Client side
var socket = io.connect('http://localhost:8082/client');
Why, in the above code, am I not getting the 'Client connected' message in my console?
So, turns out this is a very simple issue, as I suspected. The client uses the connect event, but the server uses connection.
The code should look like:
var clients = io
.of('/client')
.on('connection', function (socket) {
// This is never getting run
console.log('Client connected');
});

Resources