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

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 */);

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);
});

nodejs socket emit return undefined

I am trying to send to clients whenever a new connection issued.
My server side javascripts is :
var clients = 0;
io.sockets.on('connection', function (socket) {
clients ++;
console.log(clients);
socket.broadcast.emit('connect',socket.clients);
}
and my client side js to handle:
socket.on('connect', function (data) {
console.log('on'+data);});
the output is undefined (on undefined)
Where 's things wrong?
socket.broadcast.emit('connect',socket.clients);
^^^^^^^^^^^^^^ this should be 'clients'
Also, connect is a pre-defined event with socket.io, so you shouldn't reuse it or it might give unexpected results.
FWIW: socket.broadcast.emit will send a message to all connections except the current one. If that's not what you want (you want the message to be sent to all connections), use io.sockets.emit instead).

socket.io not working on several clients

I'm trying to build a simple chat client and am having some issues getting it working across multiple clients. Chances are I've missed something really simple. When I send something from one client it is logged in that client but not in any others.
Server:
var io = require('socket.io').listen(5000);
io.sockets.on('connection', function (socket) {
socket.on('send', function (data) {
socket.emit('receive', data);
});
});
Client:
var socket = io.connect('http://localhost:5000');
socket.on('receive', function(data){
console.log("Data received at " + new Date() + ": " + data);
});
The socket variable that gets passed to your callback function is a handle on the client that connected, so socket.emit is behaving correctly, i.e. it should only send to the client that originated it.
Try:
socket.broadcast.emit('receive', data);
to send to everybody except the originating client, or
io.sockets.emit('receive', data);
to send to all clients including the originator.
You want to emit on all sockets, not just the one that sent the message.
So you should be using:
io.sockets.emit('recieve', data);
This is assuming that you aren't logging the data on the sending client before sending it to the server. In that case you'll want to use:
socket.broadcast.emit('recieve', data);
Which will send the message to all connected clients except the sender.
See here for reference on Socket.io
Edit: Trevor beat me to it. However, for some additional clarification: io.sockets is the same as io.of(''). Which is handy to know for when you start using namespaces in a scoket.io app.

Socket.io dilemma with clients.length (where clients === io.sockets.clients();)

Normally, when I send some JSON from one client to another, it works fine. But if there is only one client, it still sends packets. My solution was to (on the server-side, in node.js):
var clients = io.sockets.clients();
if(clients.length > 1){
// send stuff to other client
}
But when I do that, something extraordinarily strange occurs. I'll open up a client, start instigating the actions during the if statement, and the console, which prints the JSON before sending it, does nothing, because there is only one client. When I open up another client and instigate the actions during the if statement, the console will print out the JSON and send it to my other client. However, if I go over to my first client that I opened and instigate the actions in the if statement, the console won't print anything out, and it won't send anything. Why? I tried changing the if statement to say:
if("hello" === "hello"){
// do the same stuff as before
}
and both clients could send JSON to one another, but because I had changed the if statement, with one client open I would still send useless packets. For obvious reasons, the optimal situation would be if it wouldn't send packets with one client, but would send packets properly with more than one.
I hope that was clear, I'm sorry if that wasn't.
If I need to, I'll post more code.
EDIT:
Here is the code that updates the array:
var clients = io.sockets.clients();
io.sockets.on("connection", function (socket) {
clients.length++;
socket.on("disconnect", function() {
clients.length--;
console.log(clients.length + " clients are connected");
});
console.log(clients.length + " clients are connected");
});
Haven't done any note.js lately, maybe this is bogus. But I thought: maybe the clients variable is defined for each client when he connects, and not updated later on. This seems the logic thing to me. I think that what you need to do is: fire an event to all clients when a new client connects, and update the "clients" variable.
I'm not sure how your code works (what's this: clients.length++ ?? Incrementation of array's length??) but try doing this the "normal" way:
var clients;
io.sockets.on("connection", function (socket) {
clients = io.sockets.clients();
socket.on("disconnect", function() {
clients = io.sockets.clients();
console.log(clients.length + " clients are connected");
});
console.log(clients.length + " clients are connected");
});
or even better (without holding global reference to connected users):
function get_clients() {
var clients = io.sockets.clients();
console.log(clients.length + " clients are connected");
}
io.sockets.on("connection", function (socket) {
socket.on("disconnect", function() {
get_clients();
});
get_clients();
});
Because io.sockets.clients() returns the array of all connected clients at the moment of calling it (perhaps that's why you get this strange behaviour).

Categories

Resources