I am using socket.io in one of express route to populate data from server and send it to on client with different event names, firstsocket and secondsocket.
var io
router.get('/start', function(req, res, next) {
io = req.app.get('socketio');
var socketlist = [{name:"firstsocket"},{name:"secondsocket"}]
for (var key in socketlist){
myInterval = setInterval(function(){
JsonObj.marks = socketlist[key].name+' '+parseInt(Math.random()*100);
io.emit(socketname, JsonObj);
}, 2000);
}
});
it is working and i can see the data on client console for these to socket events. Now i want to stop one of the socket event based on user button click. I am not getting idea to list and stop sockets.
router.get('/stop', function(req, res) {
if(req.socketname=='firstsocket') {
//stop and destroy firstsocket
}
if(req.socketname=='secondsocket') {
//stop and destroy secondsocket
}
res.redirect('/');
});
please suggest, how to identify and stop one socket session out of multiple sessions.
Thanks
If you store the socket.id information of each socket within your
var socketlist = [{name:"firstsocket"},{name:"secondsocket"}]; array,
then you would be able to close a socket connection by doing;
io.sockets.sockets[socketlist[req.socketname].socket_id].disconnect(true);
Though, I would recommend you to check if
io.sockets.sockets[socketlist[req.socketname].socket_id]
returns undefined before accessing it's disconnect property.
If you try to access disconnect property of an already closed socket, the code above will return undefined and you will have an error thrown saying
"Can't access the property disconnect of undefined"
Final code should be something like this;
if (io.sockets.sockets[socketlist[req.socketname].socket_id]) {
io.sockets.sockets[socketlist[req.socketname].socket_id].disconnect(true);
}
You can get the socket.id information of a socket on the initial connection to the server.
I'd advise you to move your io decleration out of the route and declare it like this with your socket list;
var io = require('socket.io')(server);
var socketlist = [], first_socket_connected = false;
The server variable should be your express server.
Then, use the code below to receive socket connections and push to your socket list;
io.on("connection", function(socket) {
socketlist.push({name: first_socket_connected ? "secondsocket" : "firstsocket", id: socket.id});
first_socket_connected = true;
});
Related
I'm trying to learn node.js cluster with socket.io to create a chat application... the problem is that I can't seem to get things working.
i've been trying to go through all the tutorials including the one that I get from this http://stackoverflow.com/questions/18310635/scaling-socket-io-to-multiple-node-js-processes-using-cluster/18650183#18650183
when I try to open two browsers, the messages does not go to the other browser.
here's the code that i got
var express = require('express'),
cluster = require('cluster'),
net = require('net'),
socketio = require('socket.io'),
socket_redis = require('socket.io-redis');
var port = 3000,
num_processes = require('os').cpus().length;
if (cluster.isMaster) {
// This stores our workers. We need to keep them to be able to reference
// them based on source IP address. It's also useful for auto-restart,
// for example.
var workers = [];
// Helper function for spawning worker at index 'i'.
var spawn = function(i) {
workers[i] = cluster.fork();
// Optional: Restart worker on exit
workers[i].on('exit', function(code, signal) {
console.log('respawning worker', i);
spawn(i);
});
};
// Spawn workers.
for (var i = 0; i < num_processes; i++) {
spawn(i);
}
// Helper function for getting a worker index based on IP address.
// This is a hot path so it should be really fast. The way it works
// is by converting the IP address to a number by removing non numeric
// characters, then compressing it to the number of slots we have.
//
// Compared against "real" hashing (from the sticky-session code) and
// "real" IP number conversion, this function is on par in terms of
// worker index distribution only much faster.
var worker_index = function(ip, len) {
var s = '';
for (var i = 0, _len = ip.length; i < _len; i++) {
if (!isNaN(ip[i])) {
s += ip[i];
}
}
return Number(s) % len;
};
// Create the outside facing server listening on our port.
var server = net.createServer({ pauseOnConnect: true }, function(connection) {
// We received a connection and need to pass it to the appropriate
// worker. Get the worker for this connection's source IP and pass
// it the connection.
var worker = workers[worker_index(connection.remoteAddress, num_processes)];
worker.send('sticky-session:connection', connection);
}).listen(port);
} else {
// Note we don't use a port here because the master listens on it for us.
var app = new express();
// Here you might use middleware, attach routes, etc.
app.use('/assets', express.static(__dirname +'/public'));
app.get('/', function(req, res){
res.sendFile(__dirname + '/index.html');
});
// Don't expose our internal server to the outside.
var server = app.listen(),
io = socketio(server);
// Tell Socket.IO to use the redis adapter. By default, the redis
// server is assumed to be on localhost:6379. You don't have to
// specify them explicitly unless you want to change them.
io.adapter(socket_redis({ host: 'localhost', port: 6379 }));
// Here you might use Socket.IO middleware for authorization etc.
io.on('connection', function(socket) {
console.log('New client connection detected on process ' + process.pid);
socket.emit('welcome', {message: 'Welcome to BlueFrog Chat Room'});
socket.on('new.message', function(message) {
socket.emit('new.message', message);
})
});
// Listen to messages sent from the master. Ignore everything else.
process.on('message', function(message, connection) {
if (message !== 'sticky-session:connection') {
return;
}
// Emulate a connection event on the server by emitting the
// event with the connection the master sent us.
server.emit('connection', connection);
connection.resume();
});
}
If I understand correctly, your problem is that the messages from a client are not broadcasted to the other clients. you can solve this easily using :
io.on('connection', function(socket) {
console.log('New client connection detected on process ' + process.pid);
socket.emit('welcome', {message: 'Welcome to BlueFrog Chat Room'});
socket.on('new.message', function(message) {
socket.emit('new.message', message); // this line sends the message back to the emitter
socket.broadcast.emit('my message', msg); // this broadcasts the message to all the clients
})
});
There are different ways to emit a message. The one you're using emits the message only to the socket that first sent a 'new.message' message to the server. Which means that a socket will receive the message that you emit there only if it first sent a message 'new.message'. That's why, in your browser, the client originating the message is the only one receiving it back.
Change it to:
socket.on('new.message', function(message) {
io.sockets.emit('new.message', message);//use this if even the browser originating the message should be updated.
socket.broadcast.emit('new.message', message);//use this if everyone should be updated excpet the browser source of the message.
})
Here are the different ways you can emit:
io.sockets.on('connection', function(socket) {
//This message is only sent to the client corresponding to this socket.
socket.emit('private message', 'only you can see this');
//This message is sent to every single socket connected in this
//session, including this very socket.
io.sockets.emit('public message', 'everyone sees this');
//This message is sent to every single connected socket, except
//this very one (the one requesting the message to be broadcasted).
socket.broadcast.emit('exclude sender', 'one client wanted all of you to see this');
});
You can also add sockets to different rooms when they connect so that you only communicate messages with sockets from a given room:
io.sockets.on('connection', function(socket) {
//Add this socket to a room called 'room 1'.
socket.join('room 1');
//This message is received by every socket that has joined
//'room 1', including this one. (Note that a socket doesn't
//necessarily need to belong to a certain room to be able to
//request messages to be sent to that room).
io.to('room 1').emit('room message', 'everyone in room 1 sees this');
//This message is received by every socket that has joined
//'room 1', except this one.
socket.broadcast.to('room 1').emit('room message', 'everyone in room 1 sees this');
});
So I modified the accepted answer in this thread How do I shutdown a Node.js http(s) server immediately? and was able to close down my nodejs server.
// Create a new server on port 4000
var http = require('http');
var server = http.createServer(function (req, res) { res.end('Hello world!'); }).listen(4000);
// Maintain a hash of all connected sockets
var sockets = {}, nextSocketId = 0;
server.on('connection', function (socket) {
// Add a newly connected socket
var socketId = nextSocketId++;
sockets[socketId] = socket;
console.log('socket', socketId, 'opened');
// Remove the socket when it closes
socket.on('close', function () {
console.log('socket', socketId, 'closed');
delete sockets[socketId];
});
});
...
when (bw == 0) /*condition to trigger closing the server*/{
// Close the server
server.close(function () { console.log('Server closed!'); });
// Destroy all open sockets
for (var socketId in sockets) {
console.log('socket', socketId, 'destroyed');
sockets[socketId].destroy();
}
}
However, on the client side, the client throws a ConnectionException because of the server.close() statement. I want the client to throw a SocketTimeoutException, which means the server is active, but the socket just hangs. Someone else was able to do this with a jetty server from Java
Server jettyServer = new Server(4000);
...
when (bw == 0) {
server.getConnectors()[0].stop();
}
Is it possible to achieve something like that? I've been stuck on this for a while, any help is extremely appreciated. Thanks.
What you ask is impossible. A SocketTimeoutException is thrown when reading from a connection that hasn't terminated but hasn't delivered any data during the timeout period.
A connection closure does not cause it. It doesn't cause a ConnectionException either, as there is no such thing. It causes either an EOFException, a null return from readLine(), a -1 return from read(), or an IOException: connection reset if the close was abortive.
Your question doesn't make sense.
In socket.io we create a instance and use socket like this
var server = require('http').createServer();
var io = require('socket.io')(server);
io.on('connection', function(socket){
socket.on('event', function(data){});
socket.on('disconnect', function(){});
});
server.listen(3000);
How we can create a socket event in other function like this. Is there any way or trick to this properly.
var server = require('http').createServer();
var io = require('socket.io')(server);
io.on('connection', function(socket){
socket.on('event', function(data){});
socket.on('disconnect', function(){});
});
var f1 = function (socketID) {
if(socketID){
io.to(socketID).emit('event1', 'event1 data'); //working
socket.on('call2', function (data) { // not working
});
}
}
server.listen(3000);
When you are sending a request and trying to wait for a specific response to that request, it is bit tricky to use a message-based protocol like socket.io for that situation. HTTP is perfectly designed for request/response since a single connection is used only for that one request/response and therefore the response is the response that belongs to your request.
This is not true with socket.io. It's a message based scheme. When you send a message and then wait for a message back from the other end (in a multi-user environment), you have to be very careful that you don't:
Install too many event listeners and end up with duplicates.
That the response you're getting is specifically for your original request and not for some other request that might be happening in a similar time frame.
One way to solve this issue is to add a request identifier to all your request/response messages. When you send the request, you add a unique request ID. When the response is returned, it includes that request ID and then your code can tell which response belongs with which request.
Here's an idea for how to implement the request ID concept (this needs the other end to cooperate and return the same request ID that it was sent):
var idCntr = 0;
function f1(socketID) {
if(socketID){
var id = idCntr++;
io.to(socketID).emit('event1', {id: id, data: 'event data'});
function listener(data) {
// if this is our message
if (data.id === id) {
// once our response is received, remove event handler
socket.removeListener('responseToEvent1', listener);
// process response here
// code here...
}
}
// wait for our response
socket.on('responseToEvent1', listener);
}
}
Or, here's a more object oriented scheme that adds a method to the socket object called .emitRequest():
var idCntr = 0;
socket.emitRequest = function(msg, data, responseMsg, responseFn) {
var id = idCntr++;
function listener(response) {
// if this is our message
if (response.id === id) {
// once our response is received, remove event handler
this.removeListener(responseMsg, listener);
// call response handler
responseFn(response.data);
}
}
this.emit(msg, {id: id, data: data});
this.on(responseMsg, listener);
}
Note: With both of these pieces of code, the other end of your connection needs to cooperate and return the id property of the original request so that the receiving listener can tell which response goes with which request.
I want my client-side code to send the server the user's userid when establishing the connection, then i want the server to check the database for new messages for each user that is connecting, and send the user the number of new messages it has when new messages are available.
My client-side code:
var socket = io.connect('http://localhost:8000');
socket.on('connect', function () {
socket.emit('userid', '1');
});
socket.on('new_message', function (data) {
var number_of_messages= "<p>"+data.number+"</p>";
$('#container').html(number_of_messages);
});
My server-side code:
io.sockets.on( 'userid', function (data) {
console.log('userid: '+data);
});
My problem is that the above code is not working: the userid is never received by the serverside and the on('userid') is never called.
My question is how to know which socket sent this user id and how to send to only this specific socket a certain message.
I have solved the problem by saving the clients socket and their id into a global array. this is not a good solution but it works; I know there are rooms and namespaces but I never used it..
socket.io namespaces and rooms
however,
(I used express)
client:
var socket = io.connect('http://localhost:3000',{reconnection:false});
socket.once('connect', function() {
socket.emit('join', '#{id}');
};
server:
var clients = [];
app.io.on('connection', function(socket) {
socket.on('join', function(data) {
clients.push({
ws: socket,
id: data
});
//retrive the messages from db and loop the clients array
//and socket.send(things)
}
}
I want to be able to handle all messages that are coming in from clients in a single handler.
Example client code:
var socket = io.connect('http://localhost');
socket.emit('news', { hello: 'test' });
socket.emit('chat', { hello: 'test' });
Example server code:
io.sockets.on('connection', function (socket) {
socket.on('message', function (data) {
console.log(data);
}); });
I'd like to be able to log every message even if its sent on news, chat or whatever other name using emit. Is this possible?
Note: The above server code does not work. There is nothing currently logged. I am just wondering if there is a single event which could be handled for all messages for every emit name.
That is possible by overriding socket.$emit function
//Original func
var x = socket.$emit;
socket.$emit = function(){
var event = arguments[0];
var feed = arguments[1];
//Log
console.log(event + ":" + feed);
//To pass listener
x.apply(this, Array.prototype.slice.call(arguments));
};
It's even easier on Socket.Io >3 using the socket.onAny(listener):
this.socket.onAny(m => {
..
});
This is supported out of the box now as of Socket-io 2.0.4, you simply need to register a middle ware (source from socketio-wildcard):
As of Socket.io v2.0.4 (commit), you can use a socket middleware to
catch every incoming Packet, which satisfies most of
socketio-wildcard's use cases.
io.on('connection', (socket) => {
socket.use((packet, next) => {
// Handler
next();
});
});
This is an open issue with Socket.IO.
At this time, if you really need it, you will probably have to fork Socket.IO. See 3rd-Edens comment for how to do it.