socket.io - how to access unhandled messages? - socket.io

How can you detect that you received a message on a socket.io connection that you do not have a handler for?
example:
// client
socket.emit('test', 'message');
// server
io.on('connection', function (socket) {
console.log('connection received...');
// logs all messages
socket.conn.on('message', function(data) {
console.log('this gets every message.');
console.log('how do I get just the ones without explicit handlers?');
});
socket.on('other' function(data) {
console.log('expected message');
});
}

By accessing the internals of the socket object you can determine what events it is currently listening for. You can use this server-side code to see if the current message is being handled.
io.on('connection', (socket) => {
console.log('A user connected.');
socket.on('disconnect', () => {
console.log('A user disconnected.');
});
socket.on('chat', (msg) => {
console.log('message: ' + msg);
io.emit('chat', msg);
});
socket.conn.on('message', (msg) => {
if(!Object.keys(socket._events).includes(msg.split('"')[1])) {
console.log(`WARNING: Unhandled Event: ${msg}`);
}
});
}
Once connected I am handling two events, 'disconnect' and 'chat'. After that I define a handler that catches all messages with socket.conn.on(...).
The message it receives is going to be a string that looks something like this: '2["myEventName","param1","param2"]'. By splitting it along the double quotes we can get the event name.
We then peek into the internals of socket to find all the keys of socket._events, which happen to be the event name strings. If this collection of strings includes our event name, then another handler will take care of it, and we don't have to.
You can test it from the console in the browser. Run socket.emit('some other event') there and you should see your warning come up in the server console.
IMPORTANT NOTE: Normally you should not attempt to externally modify any object member starting with an underscore. Also, expect that any data in it is unstable. The underscore indicates it is for internal use in that object, class or function. Though this object is not stable, it should be up to date enough for us to use it, and we aren't modifying it directly.
Tested with SocketIO version 2.2.0 on Chrome.

I didn't find a way to do it like socket.io, but using a simple js function to transform message into json it's doing the same job. Here you can try this:
function formatMessage(packetType, data) {
var message = {'packetType': packetType, 'data': data}
return JSON.stringify(message)
}
With:
socket.on('message', function(packet){
packet = JSON.parse(packet)
switch (packet.packetType) {
case 'init':
...
and
socket.send(formatMessage('init', {message}));

I would do so, of course it is the abstract code ... you would have to implement all the listeners and the logic to get the ids of the users to work
Client
var currentUser = {
id: ? // The id of current user
};
var socketMessage = {
idFrom: currentUser.id,
idTo: ?, // Some user id value
message: 'Hello there'
};
socket.emit('message', socketMessage);
socket.on('emitedMessage' + currentUser.id, function(message) {
// TODO: handle message
});
Server
io.on('connection', function (socket) {
// Handle emit messages
socket.on('message', function(socketMessage) {
// With this line you send the message to a specific user
socket.emit('emitedMessage-' + socketMessage.idTo, {
from: socketMessage.idFrom,
message: socketMessage.message
});
});
});
More info: http://socket.io/docs/

Related

c# SocketIoClientDotNet, node js socket.IO

c# winform tries to send node.js socket through socket.
The client is connected to server, but the socket.emit value and socket.on value do not communicate normally.
I'd like to find a solution to this.
I would like to send this name of client to the server as json type data, receive json type data from the server, read it, and send data back to json.
The data of socket.emit and socket.on are not working properly, so the code has been deleted.
c# code
private void socketLogin(string email, string pw)
{
var socket = IO.Socket("http://localhost:3000/login.html");
socket.On(Socket.EVENT_CONNECT, () =>
{
});
var loginjson = new JObject();
loginjson.Add("email", email);
loginjson.Add("password", pw);
socket.Emit("socketlogin", loginjson.ToString());
socket.On("login", (data) => {
MessageBox.Show(data.ToString());
});
}
node.js Code
var server = require('http').Server(app);
var io = require('socket.io')(server);
io.on('connection', function(socket) {
console.log('connection');
socket.on('socketlogin', function(data) {
var testLogin = { 'Login': "success" };
socket.emit('login', data);
});
});
server.listen(app.get('3000'))
in your C# you are making your socket inside a function, but at the end of the function the socket is thrown away because it is only a local variable.
There are many ways to deal with this, but essentially what you want to do is use a thread to handle the socket comms then dispatch things back to your UI thread.

Issue Broadcasting to Socket.io Rooms of A Namespace

I'm trying to set up a server that can dynamically create many rooms for many namespaces. I'm currently just trying to broadcast to sockets of a room, when a new socket has joined that room.
So far I have been able to broadcast to a specific namespace and my event listeners on the client receives the message. However when I try to broadcast to a room, of a specific namespace, my event listener doesn't receive that message.
I've turned on the Debugger mode and see the socket.io-client:socket emitting the event with the right payload and event type. So I am not sure what I am missing since the documentation also seems fairly straightforward. Any help would be much appreciated. Below is my code.
Server
const colorNs = io.of('/color');
colorNs.on('connection', (socket) => {
const { id } = socket.handshake.query;
const { id:connId } = socket.conn;
if(id) {
socket.join(id);
socket.broadcast.to(id).emit('user:connect', { id: connId });
}
socket.on('disconnect', () => {
const { id } = socket.handshake.query;
const { id:connId } = socket.conn;
socket.broadcast.to(id).emit('user:disconnect', { id: connId });
});
});
Client
const socket = io('/color?id="123"');
socket.on('user:connect', () => console.log('data', data));
Client - Debug Trace
socket.io-parser decoded 2/color,["user:connect",{"id":"IZTTPidF121JCzf9AAAO"}] as {"type":2,"nsp":"/color","data":["user:connect",{"id":"IZTTPidF121JCzf9AAAO"}]} +1ms
browser.js:133
socket.io-client:socket emitting event ["user:connect",{"id":"IZTTPidF121JCzf9AAAO"}] +3ms

Socketio: How can i send a single string over to the client

I am trying to send a string to the client like this:
socket.emit("start", "calm");
but it is throwing an error, is it because it is not an object ?
First thing first, you should make sure your socket between server-side and client-side is connect. And register event and function to the socket.
Server-side
io.sockets.on('connection', function(socket) {
console.log('socket connect' + socket.id);
// when a client connect to server within socket, server will send hello
io.emit('newMsg', "hello")
socket.on('disconnect', function() {
console.log('socket disconnect');
})
// when server receive a message, it will send to all client which connect
to the server
socket.on('data', function (data) {
console.log(socket.id +': ' + data.msg);
var message = {from: socket.id,
msg: data.msg
}
io.emit('newMsg', message)
})
}
Client-side
var socket = io('http://localhost:3000');
socket.on('connect', function (data) {
console.log(data)
})
socket.on('newMsg', function(data) {
console.log(data)
})
// function could bind on button on client side page, get input and send data
function sendData() {
var input = document.getElementsByTagName('input')
var text = input[0].value
var data = { msg: text }
socket.emit('data', data)
}
open console, the information would show in the console. When sending a message on server-side, could use 'broadcast' instead of 'emit' as well to send the message to other clients except you. Read the doc: socket.io doc

Socket.io sends two messages

I'm trying to setup socket.io and here is part of my server.js
const app = require('express')();
const http = require('http').Server(app);
const io = require('socket.io')(http, { path: '/websocket', origins:'*:*' });
io.on('connection', (socket) => {
socket.send('Hi');
socket.on('message', (message) => {
console.log(message);
socket.emit('hello', `New: ${message}`);
});
console.log('a user connected');
});
http.listen(3030, function(){
console.log('listening on *:3030');
});
and my simple client:
var socket = io('https://*******.com', {
secure: true,
path: '/websocket'
});
const input = document.getElementById('text');
const button = document.getElementById('button');
const msg = document.getElementById('msg');
button.onclick = () => {
socket.emit('message', input.value);
socket.on('hello', (text) => {
const el = document.createElement('p');
el.innerHTML = text;
msg.appendChild(el);
})
}
And if I'll click for third time I receive a 3 messages back and so on. What I'm doing wrong? I wish to send message to the server and receive modified message back.
I'm new in web sockets.
Any help appreciated.
P.S. socket.io v2.0.1
You are adding a socket.on() event handler each time the button is clicked. So, after the button has been clicked twice, you have duplicate socket.on() event handlers. When the event comes back, your two event handlers will each get called and you will think you are getting duplicate messages. Actually, it's just one message, but with duplicate event handlers.
You pretty much never want to add an event handler inside another event handler because that leads to this sort of build-up of duplicate event handlers. You don't describe (in words) exactly what you're code is trying to do so I don't know exactly what alternative to suggest. Usually, you set up the event handlers first, just once, when the socket is connected and then you will never get duplicate handlers.
So, perhaps it's as simple as changing this:
button.onclick = () => {
socket.emit('message', input.value);
socket.on('hello', (text) => {
const el = document.createElement('p');
el.innerHTML = text;
msg.appendChild(el);
})
}
to this:
button.onclick = () => {
socket.emit('message', input.value);
}
socket.on('hello', (text) => {
const el = document.createElement('p');
el.innerHTML = text;
msg.appendChild(el);
});
If you are using Angular and (probably) embedding the Socket in a Service (simpleton) you are creating a persistent listener in ngOnInit every time you load a page.
You need to create some kind of flag to know if the listener was already created in the Service from another instance of your page.

what does the socket parameter mean in the callback in socket.io/websocket?

In socket.io example code we have something like this: (probably similar in other websocket framework/libraries)
io.on('connection', function (socket) {
io.emit('this', { will: 'be received by everyone'});
socket.on('private message', function (from, msg) {
console.log('I received a private message by ', from, ' saying ', msg);
});
socket.on('disconnect', function () {
io.emit('user disconnected');
});
});
But I am not sure what this socket stands for. Is it the latest connected socket?
UPDATED:
Suppose I have used a list to store sockets with different id:
let list = {};
Then
import socketActions from './socketactions';
io.on('connection', function(socket) {
return socketActions(socket, list);
}
in socketactions.js:
function socketActions(socket, list) {
socket.id = Math.random();
list[socket.id] = socket;
socket.on('init', function(data) {
// process data
}
socket.on('sendMsg', function(data) {
// process data
}
}
export {socketAction};
Because the IDs are different the sockets in the list will be different, meaning different user connections. Now somewhere in my server I want to broadcast to other users in the network:
for (const i in list) {
const socket = list[i];
socket.broadcast.emit('timeToDoSomething', handler);
}
Now what is the difference between the socket in the list and the socket I used in the io.on('connection', function(socket) {});?
Now what is the difference between the socket in the list and the
socket I used in the io.on('connection', function(socket) {});?
There is no difference, they contain the same socket objects. Your code:
list[socket.id] = socket;
just saved the socket object into your own data structure so you could later reference it via your list data structure.
Note - you don't have to make your own map of the sockets like this. socket.io keeps one for you already. Instead, you can just access:
io.sockets.connected
at any time. It is a map with the id as the key and the socket as the value.
// given an id, get a socket
let socket = io.sockets.connected[someSocketId];
// send a message to just that socket
socket.emit("hello");
In addition, if you want to send a message to all connected sockets, you can just use:
io.emit('timeToDoSomething', data);
This will automatically iterate through all the connected sockets and send each one the same message.

Resources