Socket.io 1.1 - How to sent data from client when connecting initially - node.js

I want functionality similar to this
Client
var socket=io.connect(url,data);
Server
io.on('connection',function(socket){
//get data here in the socket object or in other way
})
I know that the data can be obtained by emitting after connecting but I want to know whether there's a way to send data when connecting initially.

The best you can do is pass data along with the URL
var socket = io.connect(url + "?data=value");
Which will be available in socket.handshake.query on the server
io.on('connection',function(socket){
var data = socket.handshake.query.data; // => "value"
});
Or if you're using passport.socketio you'll have the socket.request.user to identify the user.

Related

How to connect clients with a preset ID on a socket server?

My setup looks like this:
Client --> AuthenticationService --> REST-API --> MessageBroker(WebSocket) --> Client(s)
When a client is authenticated in the system, it gets a token ID. Now, when any client is changing a value via the REST-API, I want to push this change through websockets to every client BUT the one who changed it.
Therefore I want to filter my socket.clients[] through their token IDs.
When I transmit the change, it is easy: I'll just send the token-ID until the REST-API.
But I need to somehow connect to the socket with the exact same
tokenID. How can I accomplish this? Any best practices here?
That's the test client code:
(function() {
const ws = new WebSocket('ws://localhost:8080');
const id = 123123
ws.onopen = () => {
console.log('websocket is connected ...')
// sending the id to the socket after connecting
ws.send('connected', id)
}
})
But now the problem is: How do I know on the socket which message is meant to transport the id and which are the just normal messages?
I don't want to check EVERY message from the client and see if it's an
id message.
Any help here? What's a good practice to connect clients with a socket with a preset ID?
To answer my own question:
When the client is connecting to the websocket, just pass a parameter to the url:
const webSocket = new WebSocket('ws://127.0.0.1:8080?tokenID=123')
In the backend you can get the tokenID via url.parse:
const id = url.parse(req.url, true).query.tokenID

Combining Nodejs Net socket and Socket IO

I have a windows application (Built on C# as windows service) that sends data to NodeJs Net Socket, So since Socket.IO helps making a Web Application a live one , without the need of reload. How can i allow Socket.IO stream the received data from NodeJs Net Socket to the Web Application , in the exact moment the Net Socket receives data from C#?
So in the code that receives the socket data from C#:
var net = require('net');
net.createServer(function (socket) {
socket.on('data', function (data) {
broadcast(socket.name + "> \n" + data + " \n", socket);
socket.end("<EOF>");
//send data to web interface , does it work that way?
//SomeFooToSendDataToWebApp(Data)
});
});
Further more for the Socket.IO i have those lines , which i cant really figure out how to deal with them:
//Should it listen to net socket or web socket?
server.listen(8080);
// Loading socket.io
var io = require('socket.io').listen(server);
// It works but only for one request
io.sockets.on('connection', function (socket2) {
socket2.emit('message' , 'Message Text');
});
P.S: I am new to nodejs & socket.io , so if its possible as well to explain their behavior.
Edit 1 : My Front End Javascript to check it if it has any problems:
//for now it listens to http port , which Socket.IO listens to
var socket = io.connect('http://localhost:8080');
var myElement = document.getElementById("news");
socket.on('message', function(message) {
document.getElementById("news").innerHTML = message;
})
Edit 2 : Did follow jfriend00's answer as it seems my previous code tries were trying to send messages to an unknown socket, i only added this since i needed it to be sent to all the connected clients , so only one line fixed it !
socket.on('data', function (data) {
broadcast(socket.name + "> \n" + data + " \n", socket);
socket.end("<EOF>");
//send data to web interface , does it work that way?
//The Added code here:
io.emit('message',data + " more string");
});
It's a bit hard to tell exactly what you're asking.
If you have some data you want to send to all connected socket.io clients (no matter where the data came from), then you can do that with:
io.emit("someMessage", dataToSend);
If you want to send to only one specific connected client, then you have to somehow get the socket object for that specific client and then do:
socket.emit("someMessage", dataToSend);
How you get the specific socket object for the desired connected client depends entirely upon how your app works and how you know which client it is. Every socket connection on the server has a socket.id associated with it. In some cases, server code uses that id to keep track of a given client (such as putting the id in the session or saving it in some other server-side data). If you have the id for a socket, you can get to the socket with the .to() method such as:
io.to(someId).emit("someMessage", dataToSend);
Your question asked about how you send data received from some C# service over a normal TCP socket. As far as sending it to a socket client, it does not matter at all where the data came from or how you received it. Once you have the data in some Javascript variable, it's all the same from there whether it came from a file, from an http request, from an incoming TCP connection in your C# service, etc... It's just data you want to send.
You can try the following, simple server:
const io = require('socket.io')(8080);
io.on('connection', socket => {
console.log('client connected');
socket.on('data', data => {
io.emit('message', data);
});
});
console.log('server started at port 8080');
It should work if I understand the problem correctly.
And maybe document.getElementById("news").innerHTML += message; in the html client code to see what really happens there?
socket2 means your client which just connected. So you can store these connections to send data to them (helpful for broadcast).
If you get data from windows service via some polling mechanism, on this step you can send this message to your connected clients. So keep your connections in a array to send specific messages each client afterwards

Websockets & NodeJS - Changing Browser Tabs & Sessions

I've started writing a node.js websocket solution using socket.io.
The browsers connects to the node server successfully and I get see the socket.id and all config associated with console.log(socket). I also pass a userid back with the initial connection and can see this on the server side to.
Question: I'm not sure the best way to associate a user with a connection. I can see the socket.id changes every page change and when a tab is opened up. How can I track a user and send 'a message' to all required sockets. (Could be one page or could be 3 tabs etc).
I tried to have a look at 'express-socket.io-session' but I'm unsure how to code for it and this situation.
Question: I have 'io' and 'app' variables below. Is it possible to use the 2 together? app.use(io);
Essentially I want to be able to track users (I guess by session - but unsure of how to handle different socket id's for tabs etc) and know how to reply to user or one or more sockets.
thankyou
The best way to handle the situation is rely on SocketIO's rooms. Name the room after the user's unique ID. This will support multiple connections out of the box. Then, whenever you need to communicate with a particular user, simply call the message function and pass in their id, the event, and any relevant data. You don't need to worry about explicitly leaving a room, SocketIO does that for you whenever their session times out or they close their browser tab. (We do explicitly leave a room whenever they log out though obviously)
On the server:
var express = require('express');
var socketio = require('socket.io');
var app = express();
var server = http.createServer(app);
var io = socketio(server);
io.on('connect', function (socket) {
socket.on('userConnected', socket.join); // Client sends userId
socket.on('userDisconnected', socket.leave); // Cliend sends userId
});
// Export this function to be used throughout the server
function message (userId, event, data) {
io.sockets.to(userId).emit(event, data);
}
On the client:
var socket = io('http://localhost:9000'); // Server endpoint
socket.on('connect', connectUser);
socket.on('message', function (data) {
console.log(data);
});
// Call whenever a user logs in or is already authenticated
function connectUser () {
var userId = ... // Retrieve userId somehow
if (!userId) return;
socket.emit('userConnected', userId);
}
// Call whenever a user disconnects
function disconnectUser () {
var userId = ... // Retrieve userId somehow
if (!userId) return;
socket.emit('userDisconnected', userId);
}

Reconnect socket in disconnect event

I am trying to reconnecct the socket after the disconnect event is fired with same socket.id here is my socket config
var http = require('http').Server(app);
var io = require('socket.io')(http);
var connect_clients = [] //here would be the list of socket.id of connected users
http.listen(3000, function () {
console.log('listening on *:3000');
});
So on disconnect event i want to reconnect the disconnected user with same socket.id if possible
socket.on('disconnect',function(){
var disconnect_id = socket.id; //i want reconnect the users here
});
By default, Socket.IO does not have a server-side logic for reconnecting. Which means each time a client wants to connect, a new socket object is created, thus it has a new id. It's up to you to implement reconnection.
In order to do so, you will need a way to store something for this user. If you have any kind of authentication (passport for example) - using socket.request you will have the initial HTTP request fired before the upgrade happened. So from there, you can have all kind of cookies and data already stored.
If you don't want to store anything in cookies, the easiest thing to do is send back to client specific information about himself, on connect. Then, when user tries to reconnect, send this information again. Something like:
var client2socket = {};
io.on('connect', function(socket) {
var uid = Math.random(); // some really unique id :)
client2socket[uid] = socket;
socket.on('authenticate', function(userID) {
delete client2socket[uid]; // remove the "new" socket
client2socket[userID] = socket; // replace "old" socket
});
});
Keep in mind this is just a sample and you need to implement something a little bit better :) Maybe send the information as a request param, or store it another way - whatever works for you.

Identify a websocket from an ExpressJS request

How can one use an Express POST request as the basis for a socket.io broadcast (instead of a socket message)?
var app = express();
var server = require('http').createServer(app);
var io = require('socket.io')(server);
app.post('/campaigns', function(req, res, next) {
var campaign = new Campaign(req.body);
campaign.save(function(err, campaign) {
if (err) {
next(err);
} else {
res.json(campaign);
// how to broadcast a message to everyone
// except the sender of this POST request?
io.of('/campaigns').emit('new', campaign);
}
});
});
Very simple.
Each time you establish a connection to server, your socket object will have id associated with this connection. Save it on client side in some variable.
Then each time you post a request to server add socket id to query parameters. Upon receiving POST request on server side broadcast the message to all users and socket id to message. On client side modify on message event by adding a logic to skip/hide received message if client's socket id is equal to socket id received as a extra parameter in message.
Pitfalls
May not work if for some reason after POST request client was disconnected and reconnected to server - in this case upon receiving a message back client will have new socket id that is different from what it had before sending POST request. In that case you will have to come up with some more connection-independent client ID scheme to identify client and use it instead of socket.id as identifier. You may try to use sessions.
Client will still receive message even if it won't be displayed.
Not good to combine client-server "intercommunication" methods and use one from another and vice versa.

Resources