socket.io connection still exists after disconnection - node.js

I am trying to forward message from Redis pubsub to socketio client by using nodejs EventEmitter.
var events = require('events');
var subscriber = redis.createClient();
var app = express();
var localEmitter = new events.EventEmitter();
var server = require('http').createServer(app);
var io = require("socket.io")(server, {secure: 'true'});
io.on('connection', function (socket) {
localEmitter.on('FORWARDING', function(message)) {
console.log(socket.id + ': localEmitter is forwarding messages');
}
socket.on('disconnect', function(){
console.log(socket.id + ' disconnected);
})
};
subscriber.on('message', function (channel, message) {
console.log("Got message from redis");
localEmitter.emit('FORWARDING', encoded);
});
But if I refresh the webpage, the websocket connection disconnects and reconnects, the disconnect method can be triggered, but the localEmitter still forwarding messages via the old socket id.
The logs look like:
pxw8pcocxI3O2ru3AAAA: localEmitter is forwarding message
0BX2bVYoAn2g2JtMAAAB: localEmitter is forwarding message
0BX2bVYoAn2g2JtMAAAB disconnected
pxw8pcocxI3O2ru3AAAA: localEmitter is forwarding message
0BX2bVYoAn2g2JtMAAAB: localEmitter is forwarding message
...

Remove event emitter when socket disconnects
io.on('connection', function(socket) {
localEmitter.on('FORWARDING', mymessage);
function mymessage(message) {
console.log(socket.id + ': localEmitter is forwarding messages');
}
socket.on('disconnect', function() {
localEmitter.removeListener('FORWARDING', mymessage);
console.log(socket.id + ' disconnected');
});
});
You can also use the concept of room for the same.

Related

Nodejs socket write to all connections

I have a socket server in node. When it revives a new message, it writes it to the socket. But from which it has revived, writes to the corresponding socket, not all connections.
Server.js
var server = net.createServer(function(sock){
console.log('new client connected');
sock.on('data', function(data) {
console.log('Server received');
// ** NOT sending to all clients **
sock.write('broadcasting to others...');
});
});
Client.js
var client = new net.Socket();
client.connect(PORT, HOST, function() {
console.log('Client connected to: ' + HOST + ':' + PORT);
// Write a message to the socket as soon as the client is connected, the server will receive it as message from the client
client.write('Client is connected!!');
});
client.on('data', function(data) {
console.log('Client received: ' + data);
});
How can I broadcast one client message to all other clients?
Following up on my suggestion to use a Set to keep track of all the connected sockets, this is one way to implement that. This implementation maintains that Set as connections come and go by listening to both the connect event and the end event.
This implementation also supports a desirable feature to send to all connected sockets EXCEPT the one that triggered the event (which I think is what your situation would want):
// Set of all currently connected sockets
const connectedSockets = new Set();
// broadcast to all connected sockets except one
connectedSockets.broadcast = function(data, except) {
for (let sock of this) {
if (sock !== except) {
sock.write(data);
}
}
}
const server = net.createServer(function(sock){
console.log('new client connected');
connectedSockets.add(sock);
sock.on('end', function() {
connectedSockets.delete(sock);
});
sock.on('data', function(data) {
console.log('Server received');
connectedSockets.broadcast(data, sock);
});
});
I believe you can always keep the socket reference for each client in an array when they established connection to the server. To broadcast, simply loop the array and use perform the write()
var clients = [];
var server = net.createServer(function(sock){
console.log('new client connected');
clients.push(sock);
sock.on('data', function(data) {
console.log('Server received');
for(var i = 0; i < clients.length; i++) clients[i].write('broadcasting..');
});
});
Or if you have the control on both server and client, I think it is better to use websocket or socket.io as it offer broadcast feature.

Having problems sending private message in a socket.io room using redis

I'm trying to build a secure private facebook like messaging system using laravel, redis pub/sub and socket io. All the console.log functions log the messages to say everything went through on the node server and everything works fine untill I try and emit the message to the client. When I try to emit the message to the client nothing at all happens.
Although I don't think my controller method on laravel is of significance here it is anyway. You can skip the Laravel controller if it's not necessary
Laravel Message Controller:
public function store($id, Request $request)
{
//Stores message in $message
//Connects redis
$redis = Redis::connection();
$data = ['message' => $request->input('message'), 'user' => Auth::user()->name,
'room' => $message->conversation_id];
$redis->publish('message', json_encode($data));
return Redis::get('message');
response()->json([]);
}
Redis stuff being published in JSON output:
{message: 'some message', user: 'john doe', room: 1}
Node Server
var app = require('express')();
var server = require('http').Server(app);
var io = require('socket.io')(server);
var redis = require('redis');
server.listen(3000);
io.on('connection', function (socket) {
console.log("client connected");
var redisClient = redis.createClient();
redisClient.subscribe('message');
redisClient.on("message", function(channel, data) {
data = JSON.parse(data);
socket.join(data.room, function() {
console.log('Joined room '+data.room);
});
console.log("new message add in queue "+ data.room + " channel");
socket.to(data.room).emit(channel, data);
});
socket.on('disconnect', function() {
redisClient.quit();
});
});
Client Side JS
var socket = io.connect('http://localhost:3000');
socket.on('message', function (data) {
//Just console the message and user right now.
console.log(data.message+" " + data.user);
});
I don't know if my problem is that I'm not specifying the room on the client. If so is there any way of emitting the data to the client without specifying the room in the client side code? Why can't I emit the message to the client?

Node.js express websocket not broadcasting to all connected clients

Im trying to create a node websocket for messaging and broadcasting using openshift. Below is my code.
var WebSocketServer = require('ws').Server;
var http = require('http');
var ipaddr = opneshift_ip;
var port = openshift_port;
var server = http.createServer();
var wss = new WebSocketServer({server: server, path: '/connectserv'});
wss.broadcast = function(data) {
for(var i in this.clients) {
console.log(this.clients[i]);
this.clients[i].send(data);
}
};
wss.on('connection', function(ws) {
console.log('a client connected');
ws.on('message', function(data) {
console.log('>>> ' + data);
ws.send('got '+data);
if (data == 'broadcst') {
console.log('broadcst');
wss.broadcast('Hi All');
}
});
ws.on('close', function() {
console.log('Connection closed!');
});
ws.on('error', function(e) {
console.log(e);
});
});
console.log('Listening at IP ' + ipaddr +' on port '+port);
server.listen(port,ipaddr);
When any client connects, console writes "a client connected".
When any client sends message, console writes ">>> message" and im getting the same at client as well ("got message")
But when multiple clients are connected, if i want to broadcast a message to all connected clients, i send "broadcst" as message. Than goes into
if (data == 'broadcst') {
console.log('broadcst');
wss.broadcast('Hi All');
}
But only the client which sends get the message.
How to make all clients to get the message?
Does each client creates separate session?
How to use redis here?
Any quick help appreciated.
Thanks.
Try
wss.broadcast = function(data) {
for(var i in wss.clients) {
console.log(wss.clients[i]);
wss.clients[i].send(data);
}
};
broadcasting with wss

Socket.io server to server (sending message to specific server)

I have a specific situation. I have client (browser) which connects to server A. Server A is connected to server B and C. When client sends message to server A, I need to send message to specific server which means to one of the servers B or C, not both of them. Generally I need separated communication between servers but I have only broadcasted communication. Message from server A to another server can't be seen on all connected servers.
How can I send messages directly to one of the servers ? Here is my code snippet for servers. I just change ports for each server and connect them.
// Load requirements
var PORT = process.env.PORT || 8080;//just change port for other servers
var express = require("express");
var app = express();
var http = require("http").Server(app);
var io = require("socket.io")(http);
app.use(express.static(__dirname + '/public'));
var client = require('socket.io-client');
var socket1 = client.connect('http://localhost:8081', { reconnect: true });//connection to server B
var socket2 = client.connect('http://localhost:8082', { reconnect: true });//connection to server C
// Add a connect listener
io.on('connection', function (socket) {
console.log('Client connected.');
//when server receive message from client
socket.on('message_from_browser', function (message) {
console.log("Message from browser broadcasted: " + message.text);
var updated_message = {
text: message.text,
port: PORT
};
// send message to server B
socket1.emit('server_message', updated_message);//send message to server B
});
// Disconnect listener
socket.on('disconnect', function () {
console.log('Client disconnected.');
});
});
socket1.on('connect', function () {
socket1.on('server_message', function (message) {
console.log('RECEIVED MESSAGE FROM ANOTHER SERVER ON PORT '+ message.port + ": " + message.text);
});
//change server name
console.log('Connected to server B!');
});
socket2.on('connect', function () {
socket2.on('server_message', function (message) {
console.log('RECEIVED MESSAGE FROM ANOTHER SERVER ON PORT '+ message.port + ": " + message.text);
});
//change server name
console.log('Connected to server C!');
});
http.listen(PORT, function (req, res) {
console.log("Server Started on port: " + PORT);
});
You have a naming conflict with the variable name socket. It is defined as both your connection to server B and as an argument in your .on('connection', function(socket) {...}) callback.
To fix that, change this:
var socket = client.connect('http://localhost:8081', { reconnect: true });//connection to server B
var socket2 = client.connect('http://localhost:8082', { reconnect: true });//connection to server C
To this:
var socket1 = client.connect('http://localhost:8081', { reconnect: true });//connection to server B
var socket2 = client.connect('http://localhost:8082', { reconnect: true });//connection to server C
And, then refer to the server B connection as socket1, not socket.
The variable named socket is already defined as an argument in this so you cannot reach the outer socket variable when it has a conflicting name:
// Add a connect listener
io.on('connection', function (socket) {
// socket variable name ^^^^^^
console.log('Client connected.');
//when server receive message from client
socket.on('message_from_browser', function (message) {
console.log("Message from browser broadcasted: " + message.text);
var updated_message = {
text: message.text,
port: PORT
};
// send message to server B
socket1.emit('server_message', updated_message);//send message to server B
});
// Disconnect listener
socket.on('disconnect', function () {
console.log('Client disconnected.');
});
});
And there were no listeners for incoming server messages so you need to add listeners for socket1 and socket2.
io.on('connect', function(socket1){
socket1.on('server_message', function (message) {
console.log('RECEIVED MESSAGE FROM ANOTHER SERVER ON PORT '+ message.port + ": " + message.text);
});
});
io.on('connect', function(socket2){
socket2.on('server_message', function (message) {
console.log('RECEIVED MESSAGE FROM ANOTHER SERVER ON PORT '+ message.port + ": " + message.text);
});
});
Use one variable and configs to track others hosts, try:
Updated to fix some bugs:
// Load requirements
var PORT = process.env.PORT || 8081;//just change port for other servers
var express = require("express");
var app = express();
var http = require("http").Server(app);
var io = require("socket.io")(http);
var async = require('async'); // async is optional for this example ...
var client = require('socket.io-client');
app.use(express.static(__dirname + '/public'));
// save hosts here ...
var otherServers = {
server1: {
url: 'http://localhost:8082'
},
server2: {
url: 'http://localhost:8083'
},
};
// Add a connect listener
io.on('connection', function (socket) {
console.log('Client connected.');
//when server receive message from client
socket.on('message_from_browser', function (message) {
console.log("Message from browser broadcasted: " + message.text);
var updated_message = {
text: message.text,
port: PORT
};
// choice how server will receive this message ...
// then send it
otherServers.server1.client.broadcast.emit('server_message', updated_message);
});
// Disconnect listener
socket.on('disconnect', function () {
console.log('Client disconnected.');
});
});
async.each(otherServers, function forEachOtherServer(otherServer, next) {
//connect to another server
otherServer.client = client.connect(otherServer.url, { reconnect: true });
// to something more if need in every client connection ...
otherServer.client.on('connect', function (x) {
otherServer.client.on('server_message', function (message) {
console.log('RECEIVED MESSAGE FROM ANOTHER SERVER ON PORT '+ message.port + ": " + message.text);
//socket.broadcast.emit('message_from_server', message_server);
});
console.log('Connected!');
});
next();
}, function afterConnectInAllServers(err) {
if (err) throw err;
// to something after connect in all servers ...
});
http.listen(PORT, function (req, res) {
console.log("Server Started on port: " + PORT);
});

How to emit message from client side [node.js + socket.io]

I am trying to emit message from client side with socket.io ...
Here is my client code:
var socket = io.connect('http://localhost/');
socket.on('connect', function(data){
setStatus('connected');
socket.emit('subscribe', {channel:'update.comment'});
});
Server:
io.sockets.on('connection', function (socket) {
socket.emit('message', { text : 'Welcome!' });
socket.on('subscribe', function (data) {
socket.join(data.channel);
redisClient.subscribe(data.channel);
});
});
Also I get this error message in console:
GET
http://localhost/socket.io?EIO=3&transport=polling&t=1442169984269-1
404 (Not Found)
Full serever:
var app = require('express')();
var http = require('http').Server(app);
var redis = require('ioredis');
var io = require('socket.io')(http);
redisClient = redis.createClient();
//look for connection errors and log
redisClient.on("error", function (err) {
console.log("error event - " + redisClient.host + ":" + redisClient.port + " - " + err);
});
io.sockets.on('connection', function (socket) {
socket.emit('message', { text : 'Welcome!' });
//on subscription request joins specified room
//later messages are broadcasted on the rooms
socket.on('subscribe', function (data) {
socket.join(data.channel);
redisClient.subscribe(data.channel);
});
});
redisClient.on('ready', function(data) {
console.log('#redis ready');
});
redisClient.on("message", function(channel, message){
console.log(channel);
var resp = {'text': message, 'channel':channel};
io.sockets.in(channel).emit('message', resp);
});
http.listen(3000, function(){
console.log('Listening on Port 3000');
});
New Problem Recognized:
Your server is listening on port 3000, but you are attempting to connect on port 80. The error message http://localhost/socket.io?EIO=3&transport=polling&t=1442169984269-1 has no port number on it so that defaults to port 80.
That error message means that your server-side socket.io code is not initialized correctly and thus is not listening for the HTTP request that starts all webSocket connections so when the browser tries to connect on that URL to initiate a socket.io connection, there's nobody on the server-side listening so the web server returns a 404 error back to the browser.
If you are using Express, this is the minimal socket.io initialization to hook it into your server:
var express = require('express');
var app = express();
var server = app.listen(8081);
var io = require('socket.io').listen(server);
For a plain HTTP server, this is the minimal socket.io initialization:
var app = require('http').createServer(handler)
var io = require('socket.io')(app);
app.listen(80);
As always, if you show us the socket.io and web server initialization code you are using, we can help you better with your specific code issue.

Resources