socket.io - can't emit data from server to specific client - javascript

So I'm trying to emit data from server to one specific client upon connecting (this is server code):
io.sockets.on('connection', function(socket){
socket.id = Math.random();
//this works, but sends data to all clients, which is not what I need
socket.emit('serverMsg');
//this seems to do nothing
io.to(socket.id).emit('serverMsg');
//this also does nothing
socket.broadcast.to(socket.id).emit('serverMsg');
});
As I've commented the lines, I can emit data to all clients, but nothing happens when I try to emit to specific client with socket.id.
What am I doing wrong? There are no error messages or anything.

When a client connects, its socket.id is automatically initialized. Also, it joins a room with the same name:
Each Socket in Socket.IO is identified by a random, unguessable,
unique identifier Socket#id. For your convenience, each socket
automatically joins a room identified by this id.
If, for some reason, you wish to redefine the id, you would need to assign the socket to the corresponding room as well, since the to( ) method expects as its argument the name of the room of interest. In the code in your post, you redefine the id, but the association with the corresponding room is not established, thus the emit method emits the data into the "void" (into a room the name of which is equal to the result of Math.random(), but which contains no sockets)...
const customId = ....
socket.id = customId;
socket.join(customId);
io.to(customId).emit(...)

this work for me
const http = require('http').createServer();
const sio = require('socket.io')(http);
var port = xxxx;
var ip = "xxx.xxx.x.x";
sio.on('connection', async function(socket) {
sio.sockets.to(socket.id).emit("from_server", "your are connected");
});
http.listen(port, ip, function() {
console.log('Server active. listening on :' + ip + ":" + port);
});

Related

Socket.io emit from server is not being received by client

I've been experimenting with sockets lately, and I've ran into a bug that I'm not sure why is happening.
I created an index page with a button titled createRoom, which attempts creates a lobby/room in which other users can connect.
//index.js
createBtn.addEventListener('click', () => {
socket.emit("create-room", socket.id)
})
socket.on("redirect-host", roomId=>{
console.log("I JUST CREATED: " + roomId);
window.location.replace("/master") //lobby
})
//server.js
io.on("connection", socket => {
console.log("a user connected");
socket.on("create-room", hostId => { //receives the id of the person creating lobby
let roomId = Math.round(Math.random() * (999999 - 100000) + 100000);
socket.join(roomId)//generates room and then sends emit back to redirect host
console.log("Socket " + hostId + " created room: " + roomId);
socket.to(hostId).emit('redirect-host', roomId);
})
})
In index, there is a button you can click to generate a room which emits a create-room to server, which then creates a room and emits the room number back and tells server.js to redirect to a lobby screen (/master).
However, nothing seems to happen upon button press. My main suspect is that "redirect-host" is being sent to the wrong place, but then again I am new to sockets so I can't be sure of it.
Thank you.
EDIT: Resolved! To anyone wondering, the parameter "socket" is the connected socket. According to the socketio documentation, .to sends the emit to everyone but itself
Instead used,
io.in(roomId).emit('redirect-host', roomId);
Socket stands for the connected socket itself. Looking at the documentation:
// to all clients in room1 except the sender
socket.to("room1").emit(/* ... */);
Instead, I believe you want the server to send something to ALL clients in the room. For that, use io.in
io.in(roomId).emit('redirect-host', roomId);

Vue & Sockets: Handling sending messages back and forth

I have a simple implementation, or an attempt at one, of a messaging system just to show an alert of a message to different users. I'm using https://www.npmjs.com/package/vue-socket.io Vue Socket Io but it's just a socket.io. I am attempting to have the client subscribe to an event in mounted. The name is based on their userID. The problem is that my implementation below doesn't work to show the alerts. I can see the event being subscribed to in mount and I can see sending message console log in the server so I know that is getting fired but I don't see the alert being triggered by the emit(Chat_....
server:
io.on('connection', function(socket) {
socket.on('sendMessage', function (data) {
console.log("Sending message to" + data.user);
socket.emit(`CHAT_${data.user}`, data.msg)
});
});
client:
On the client, the userIDSelf is a user ID that is passed in as a prop. It's the User's logged in ID and in mounted, they automatically subscribe to the a chat channel with their userid appended to it, like a custom channel.
mounted() {
this.sockets.subscribe(`CHAT_${this.userIDSelf}`, (data) => {
alert(data)
});
},
there is a function sendMessage that takes the values from 2 inputs (not seen) in the template. You have to enter a user ID on who you want the message sent to and then another input with the actual message. These are sent over to the backend server listed above.
methods: {
sendMessage() {
this.$socket.emit('sendMessage', {user: this.userIDReceiver, msg: this.message})
},
}
I see a logical problem here. In your server code
io.on('connection', function(socket) {
socket.on('sendMessage', function (data) {
console.log("Sending message to" + data.user);
socket.emit(`CHAT_${data.user}`, data.msg)
});
});
the socket (User 123) which emitted sendMessage event to the server, will eventually also be the socket which will receive the emitted CHAT_456 event from the server. But User 123 socket only listens to CHAT_123 events. The socket is sending itself a message but doesn't receive it.
Possible Solutions
A - the room approach
Once a socket connects on the server, throw it in a room based on it's user id. This requires sending the userid to the server during connection, e.g. with a query parameter. In the client just add a token query parameter to the connection string like
const io = require('socket.io-client');
const socket = io("https://server-domain.com/?token=" + userid);
and through the connecting socket in a room (join) on the server side like
io.on('connection', function(socket) {
const userid = socket.handshake.query.token;
socket.join(userid);
});
then your socket sendMessage would work like this
/* ... server side */
socket.on('sendMessage', function (data) {
console.log("Sending message to" + data.user);
io.to(data.user).emit('chatMessage', data.msg);
});
B - the keep reference to the socket approach
Internally every socket has a socket id. Normally these are not exposed the user/clients. However you do have a unique user id. So let's keep a user id / socket instance - relation on the server side, so you can get a reference to the socket object for each corresponding user, using the user id.
The most basic example for it would be a in-memory store on the server side
let socketRefs = {};
io.on('connection', function(socket) {
const userid = socket.handshake.query.token;
socketRefs[userid] = socket;
});
then your socket sendMessage would work like this
/* ... server side */
socket.on('sendMessage', function (data) {
console.log("Sending message to" + data.user);
let targetSocket = socketRefs[data.user];
targetSocket.emit('chatMessage', data.msg);
});

Socket.io + express rooms

I am working on an online website with real-time chat and I've been trying to set up socket.io rooms for a few days now, but one of my custom events just doesn't emit.
My website has 2 paths, / and /play. When someone fills out a form in the / path, the website redirects them to the /play path.
const io = require('socket.io')(listener);
io.on('connection', socket => {
socket.on('add user', data => { // This event gets emitted when the user submits the form at `/`, in a client-side js file.
socket.username = data.username;
socket.room = data.room;
socket.score = 0;
socket.join(data.room);
io.sockets.in(data.room).emit('user joined', { // This event gets 'handled', in another (not the same one) client-size js file.
username: data.username,
room: data.room
});
});
socket.on('disconnect', function () {
io.sockets.in(socket.room).emit('user left', {
username: socket.username,
room: socket.room
});
socket.leave(socket.room)
});
});
In the other client-side js file:
var socket = io.connect();
let joined = 0;
socket.on('user joined', data => {
joined++;
console.log(joined, data)
const elemental = document.createElement("LI");
const info = document.createTextNode(data.username);
elemental.appendChild(info);
document.getElementById('people').appendChild(info)
});
The add user event code executes just fine, but the user joined one doesn't..
I'm almost certain that it has to do with the paths. I read on socket.io namespaces but it seems like they are just like a different type of rooms.
Can someone tell me what's wrong?
EDIT: I should mention that no errors come up.
Without seeing your whole code, I'm going to assume that the socket on client-side.js code, is not joined to the data.room room, and that's why you don't get anything on the 'user join' event listener and that happens because you probably have multiple socket.io connections on the client side code.
You have multiple ways to solve this, depending on what you're trying to achieve.
Instead of only emitting to people on the room, emit to all sockets that an user joined a specific room. io.emit('user joined') instead of io.sockets.in(data.room)...
There should only be one single var socket = io.connect(); on the front end, otherwise the socket that's emitting: add user and therefore joined to data.room is not the same socket that's listening on: user joined, and that's why you never get the event on that socket, because you have 2 different sockets, one that joined the room, and one that is doing absolutely nothing except waiting for an event that will never occur.

Check in client side if a socket.io id is still connected

I would like to check in client side if a socket id is still connected.
The version of socket.io I use is <script src="/socket.io/socket.io.js"></script>.
I have tried answers in several threads, but it did not work.
Edit 1: Actually, I have 1 server which can serve many clients. In the server I have the following code which sends the socket id to a client when it is connected:
io.sockets.on('connection', function (socket) {
console.log("LOG: just connected: " + socket.id);
socket.emit('id', socket.id);
socket.on('disconnect', function () {
console.log("LOG: just disconnected: " + socket.id)
})
})
Two clients may talk to each other via the server, that's why ClientA may (besides its own socket id) keep the socket id of ClientB. Thus, it will be useful for me to check (from an id) in the client-side if a client is still connected. It will be OK if this check needs to ask the server, I just want this check to be as simple and sure as possible.
Apparently (from your comments), clientA has a socket.id of clientB and clientA wants to know if clientB is currently connected. Since a socket.id is just a string value, there is no way for clientA to tell from just the socket.id if clientB is connected or not. That information would have to come from the server.
You can have clientA ask the server if it thinks clientB is connected (by sending the socket.id of clientB to the server in a request message) and the server could respond with what it knows about clientB's connected state.
The server maintains a list of all connected clients. One of the ways you can access that list is via a map that is indexed by socket.id. So, it would be easy for the server to see if a connected client is in the map with a given socket.id.
Here's a way you could ask your server if a given socket.id is connected. This would be your server code:
io.sockets.on('connection', function (socket) {
console.log("LOG: just connected: " + socket.id);
socket.emit('id', socket.id);
socket.on('disconnect', function () {
console.log("LOG: just disconnected: " + socket.id)
})
// use the ack function argument to send a response back
socket.on('isConnected', function(id, ackFn) {
let otherSocket = io.sockets.connected[id];
ackFn(!!otherSocket && otherSocket.connected);
});
});
And, the client would send a request and listen for the response:
socket.emit('isConnected', someId, function(result) {
console.log(someId + ": " + result ? "is connected" : "is not connected");
});
Original answer that thought you were asking how a client can tell if its own socket is connected.
A socket.io object has a .connected property that reflects what socket.io thinks is the current state of the connection.
if (socket.connected) {
// socket.io thinks it is still connected
}
You can see it being used here internally in the .emit() method:
if (this.connected) {
this.packet(packet);
} else {
this.sendBuffer.push(packet);
}
Socket.io already implements its own heartbeat sent from server to client so it will usually notice when the connection stops working. By default, it will try to reconnect, but if that reconnection does not work immediately, the socket may remain in the disconnected state while it retries further reconnects.
I suggest sending a broadcast every 30 sec or so, This way you won't loose connection to your socket.
window.setInterval(function(){
yoursocket.emit('broadcast');
}, 30000 /* 30 sec */);

Socket.io - Cant stop passing all data to all clients

I am having a issue where I am pulling data from a DB via node mysql & Express and passing it via socket.io.... but there's an issue am running into.
All users are updating with the same data rather than unique data per user.
For example:
If user A has just logged in he can see all his account details. But when user B logs in right after he can then see all his details....but it then updates user A details to show user B details as well.
I am trying to ensure user A can can only see his own and same for user B.
I have tried numerous things to stop this happening via JQuery but cant seem to find a resolution.
Below I have trimmed down a the code to a basic example:
HTML
<span id="id-val">User A</span>
<span id="user-val"></span>
Server side
server = http.createServer(app),
io = require('socket.io').listen(server);
function SQLuserData(userval) {
connection.getConnection(function (err, connection) {
connection.query('SELECT val FROM test WHERE name= ?;',
[userval],
function (err, rows) {
var accountval = rows[0]['val'];
if (accountval) {
console.log("Val : " + accountval);
UserVal(accountval);
} else {
console.log("Error | Val: " + err);
}
});
connection.release();
});
}
//Socket.io connection socket
io.sockets.on('connection', function (socket) {
socket.on('sqluser', function (userval) {
SQLuserData(userval);
});
});
//Pass val client side.
function UserVal(accountval) {
io.sockets.emit("valsocket", accountval);
}
Client side
var socket = io.connect();
//Used to grab information for that user from serverside.
$(document).ready(function () {
var userval = $('#id-val').text();
socket.emit('sqluser', userval);
});
//Grabs user value being passed from serverside and updates HTML.
socket.on("valsocket", function (accountval) {
$("#user_val").val(accountval);
});
Does anyone have any advice or potential solutions?
you need to grab and store the socket.id for each connected user
var users = {};
//Socket.io connection socket
io.sockets.on('connection', function (socket) {
socket.on('sqluser', function (userval) {
// 'userval' must be unique for each user
users[userval] = socket.id;
SQLuserData(userval);
});
});
and then use the same id to emit data ti single socket
//Pass val client side.
function UserVal(accountval, userval) {
io.sockets.socket(users[userval]).emit("valsocket", accountval);
}
for socket.io version 1.0 and above
io.to(users[userval]).emit("valsocket", accountval);
I think you want to avoid emitting the account data to all connected users, which is what Socket.IO's emit method does. It might be better have the client send a GET request to the server and respond with the account details to the individual client.
Here are some resources if you choose to use an HTTP request over Socket.IO:
jQuery GET
Express Respond
So basically the problem with your code is that you are not distinguishing between users . Since you are sending data through socket you need to be careful to whom you are sending data.
You can use socketio-auth to create a type of authentication . And then send the data as socket.emit(event, data); Where socket is an individual object per user . You can also use a cookie based session to help you with this .

Categories

Resources