Socket.io communicating from server to client not happening - node.js

i am trying to do a very simple real time notification with socket.io. for some reason i can't receive data or fire the event from server to client but from client to server yes. let me show my code:
Client Side
ngOnInit() {
this.socket.on('connect', function (res: any) {
console.log('Socket.io is connected on client side!'); // it shows on client console
});
this.socket.on('alarmsreceived', function (res: any) {
console.log(res + ' i am here now'); // is not firing
});
}
// this method fires from a click button
objectStatus = () => {
this.socket.emit('alarmsystem', 'i am client going to server');
}
Server
var io = require('socket.io').listen(server);
var connections = [];
io.of('/api/v1/monitoring').on('connect', function(socket){
connections.push(socket);
console.log('Connected %s sockets', connections.length); // i see connection on cmd
socket.on('disconnect', function() {
connections.splice(connections.indexOf(socket), 1);
console.log('Connected %s sockets', connections.length);
});
socket.on('alarmsystem', function(res) {
console.log(res); // this shows me the message from client
io.sockets.emit('alarmsreceived', 'I am server heading to client');
});
})
it seems pretty straight forward, but not firing the client event. Can someone help me what i am doing wrong here? Thanks in advance

Related

How to kick somebody out on socket

I am on a websocket (socket.io) and I want to be able to force disconnect on a given user. I use this on my server file:
// kickout
socket.on('kickout', (sckid) => { //sckid is the socket.id of the kicked-out user
io.to(sckid).emit('kicked');
});
});
// kicked out
socket.on('kicked', () => {
socket.disconnect();
});
Then I do socket.emit('kickout', 'someusersocketid'); on my frontend but it won't work for some reasons. Seems like the server listens to "kickout" alright but so to "kicked". Why is that?
Try this one:
var clients = {}
sockets.on('connection', function(socket) {
clients[socket.id] = socket;
socket.on('disconnect', function() {
delete clients[socket.id];
});
});

Angular 6 authentificate client after server restart socket.io socketio-jwt

Id like to auth eacht socket.io event on server side.
When i open angular page first, call method initSocket(login: Login), its ok.
Authentification successfull and i can send a message to server.
But if i restart server, angular reconnect to server by Htttp, but cant send a message by socketio.
In my server no messages in logs.
It seems that socketio-jwt block an clients message.
If i press F5 on client side its still ok again.
How to solve it without refreshing a page?
It seems taht i have to pass a token to each event on client side, after connection established to, but i dont know how to do it.
Angular 6:
public initSocket(login: Login): void {
this.socket = socketIo(SERVER_URL);
console.log('Socket init at' + SERVER_URL);
this.socket.emit('authenticate', { token: this.login.token });
this.socket.on('authenticated', function () {
console.log('socket is jwt authenticated');
});
this.socket.on('unauthorized', function (error, callback) {
if (error.data.type === 'UnauthorizedError' || error.data.code === 'invalid_token') {
// redirect user to login page perhaps or execute callback:
callback();
console.error('Users token has expired');
}
});
this.socket.on('disconnect', function (error) {
console.error('socket disconnect', error);
});
this.socket.on('connect_failed', function (error) {
console.error('socket connect_failed');
});
}
Server side:
io.sockets
.on('connection', socketioJwt.authorize({
secret: environment.secret,
timeout: 15000,
callback: false
})).on('authenticated', function (socket) {
clients[socket.decoded_token.id] = socket.decoded_token.login;
console.error('Connected: ', socket.decoded_token.login);
socket.on('message', async function (data) {
try {
// Проверка что пользователь пишите от себя
if (data.from === socket.decoded_token.id) {
data.totalCount = await db_helper.saveMessage(data);
if (clients[data.from] && clients[data.to]) {
io.sockets.connected[clients[data.to].socket].emit("message", data);
console.log("Sending from: " + clients[data.from].name + " to: " + clients[data.from].name + " '" + data.text + "'");
} else {
console.log('User does not exist: from=>', data.from, ':', clients[data.from], 'to=>', data.to, ':', clients[data.to]);
}
}
}
catch (error) {
console.error(error.message);
}
});
//Removing the socket on disconnect
socket.on('disconnect', function () {
});
});
This is because whenever your server/client goes offline, a new socket is created for re connection purpose and to establish a new connection i.e re connection, Server disconnects all it's previous connection from the same client, this process is asynchronous and thus is not visible to developers easily.
I would have also checked if my socket reconnection which is done is reconnected to the , by default socket reconnects to the port your client is connected to.
if that's the case then you need to reconnect with the help of io (socket manager)
There is also a possibility that your client re connection is set to false, you can check your socket properties by consoling it as follows:
this.socket.on('disconnect', function (error) {
console.log('disconnected', this)
//this sets whether the re connection is allowed or not
this.io._reconnection = true;
});
this.socket.on('reconnect', (error, callback) => {
console.log('reconnect succesfully', this);
//connect to the previously connected socket.
this.io.socket.reconnect()
});

Socket IO not properly closing connection

I'm tailing a log file and stream the new lines to a websocket.
Since I have multiple logs, I let the user choose the log file and then get the details of that log.
The problem is that when I close a connection in order to see a different log, the connection does something weird, that when I start it again, it streams the data twice. If I close the connection and re-open it again, it streams 3 times the data, so on and so forth.
My package.json:
{
"socket.io": "^2.0.3",
"socket.io-client": "^2.0.3"
}
Client side
$("#detailsBtn").click(function (e) {
e.preventDefault();
$.get('/get/details', {
// some-data
}, () => {
if (socket) socket.close();
socket = io('http://localhost:4000', {forceNew: true});
socket.on('connect', () => {
console.log('connected');
});
socket.on('newLine', function (msg) {
// do-stuff
});
});
});
$('#closeBtn').click(function () {
socket.disconnect();
socket.close();
});
Server side
app.get('/details', (req, res) => {
const tail = spawn('ssh', ['root#' + req.query.srv, req.query.script]);
io.on('connection', function (socket) {
console.log(`connect ${socket.id}`);
socket.on('disconnect', () => {
console.log(`DISconnected ${socket.id}`);
});
tail.stdout.on('data', function (data) {
socket.emit('newLine', {message: data});
});
});
return res.sendStatus(200);
});
Now when simulating the button click, I expect the socket and connection to be closed, in order to make a new one.
Server console log (each time I click the button only once)
Server listening on localhost:4000
**click on detailsBtn**
GET /get/details?srv=myserver.google.com&script=%2Fusr%2Fbin%2Ftail 304 16.003 ms - -
connect YyYHFI9CARpBHaxoAAAB
**click on closeBtn**
DISconnected YyYHFI9CARpBHaxoAAAB
**click on detailsBtn**
GET /get/details?srv=myserver.google.com&script=%2Fusr%2Fbin%2Ftail 304 6.308 ms - -
connect vzfBnUPHUqYXd5qaAAAC
connect vzfBnUPHUqYXd5qaAAAC
**click on closeBtn**
DISconnected vzfBnUPHUqYXd5qaAAAC
DISconnected vzfBnUPHUqYXd5qaAAAC
**click on detailsBtn**
GET /get/details?srv=myserver.google.com&script=%2Fusr%2Fbin%2Ftail 304 4.677 ms - -
connect 3quEe5G1gFDJ2BvrAAAD
connect 3quEe5G1gFDJ2BvrAAAD
connect 3quEe5G1gFDJ2BvrAAAD
**click on closeBtn**
DISconnected 3quEe5G1gFDJ2BvrAAAD
DISconnected 3quEe5G1gFDJ2BvrAAAD
DISconnected 3quEe5G1gFDJ2BvrAAAD
What am I doing wrong?
As you see in the console logs, the connect and disconnect shows the same socketID. This indicates that the event handler is triggered many times.
From your code you define a new event handler for 'connection' every time the '/details' route is getting a request.
So a better aproach would be...
io.on('connection', function (socket) {
console.log(`connect ${socket.id}`);
socket.on('disconnect', () => {
console.log(`DISconnected ${socket.id}`);
});
tail.stdout.on('data', function (data) {
socket.emit('newLine', {message: data});
});
});
app.get('/details', (req, res) => {
const tail = spawn('ssh', ['root#' + req.query.srv, req.query.script]);
return res.sendStatus(200);
});
So the comments here directed me to the solution.
I had duplicate event handlers for both the socket and the tail.
I called the initiation of the connection each time a user clicked the button, and I spawned a tail child process each time the URL was accessed
Here is how I fixed it:
Socket
1.Moved the io.on('connection'...) outside of the app.get handler as suggested by #alex-rokabilis
2.Created an event emmiter of my own:
const events = require('events');
const eventEmitter = new events.EventEmitter();
3.Inside io.on('connection'...), instead of listening to tail.stdout event, I listened to my eventEmitter event in order to be able to use the tail outside of the app.get handler
io.on('connection', function (socket) {
eventEmitter.on('newLine', (data) => {
socket.emit('newLine', {line: data});
});
});
4.In the app.get handler, I listen to tail.stdout.on('data'... and send an eventEmitter event that would be handled inside the io object:
app.get('/details', (req, res) => {
let tail = spawn('ssh', ['root#' + req.query.srv, req.query.script]);
tail.stdout.on('data', (data) => {
eventEmitter.emit('newLine', data.toString().replace(/\n/g, '<br />'));
});
});
5.On client, I moved the io initialization outside of the ajax call, defined socket in a way I could use further in the script.
let socket = io('http://localhost:4000', {forceNew: true});
socket.on('connect', () => {
console.log('connected');
});
socket.on('newLine', function (msg) {
// do-stuff
});
$("#detailsBtn").click(function (e) {
e.preventDefault();
$.get('/get/details', {
// some-data
});
});
Tail
This was a bit hard to find, I always thought the problem is with the socket-io rather than the tail.
Inside io.on('connection'..., I added a socket listener for an event named closeConnection that emits closeConnection to my eventEmitter, that in turn kills the tail child process:
io.on('connection', function (socket) {
eventEmitter.on('newLine', (data) => {
socket.emit('newLine', {line: data});
});
socket.on('closeConnection', () =>{
console.log('got connection close from client');
eventEmitter.emit('closeConnection');
});
});
And inside the app.get controller:
app.get('/details', (req, res) => {
let tail = spawn('ssh', ['root#' + req.query.srv, req.query.script]);
tail.stdout.on('data', (data) => {
eventEmitter.emit('newLine', data.toString().replace(/\n/g, '<br />'));
});
eventEmitter.on('closeConnection', () => {
tail.stdin.pause();
tail.kill();
});
});
And in the client, each time I want to close the connection, I just:
socket.emit('closeConnection');
That was tough.

Socket.io connected but not communicating

I have a very simple configuration in a node server with socket.io installed (a little bit more complex but essentially like this one):
var main = require('express')();
server = require('http').createServer(main);
io = require('socket.io')(server);
io.use(function(socket, next) {
console.log("middleware!");
next();
});
io.on('connection', function (socket) {
console.log('connected...');
socket.on('pong', function (data) {
console.log(data.message);
});
setTimeout(function() {
console.log("Saying hello");
socket.emit('ping', { message: 'Hello from server ' + Date.now() });
}, 1000);
});
server.listen(2080, function onCreateServerMain() {
console.log('Server main is listening on port 2080';
console.log('************************************************************');
});
In the client:
var socketIoScript,
loadSocketTimeout,
trialsToLoadSocketIo = 0,
APP_CFG = {baseUrl : "http://192.168.1.13:2080"};
function loadSocketIo(socketIoIp) {
socketIoScript = document.createElement('script');
socketIoScript.setAttribute('src', socketIoIp);
socketIoScript.setAttribute('onload', 'onSocketLoaded();');
document.head.appendChild(socketIoScript);
}
window.onSocketLoaded = function onSocketLoaded() {
if (typeof(io.connect) === 'function') {
var mSocket,
mIoSocket;
$timeout.cancel(loadSocketTimeout);
mIoSocket = new io.Manager(APP_CFG.baseUrl);
mIoSocket.connect(function(socket) {
console.log('Connected!!');
});
mIoSocket.on('error', function onSocketError(e) {
console.log('WebSocket Error ' + error);
});
mIoSocket.on('ping', function onPingReceived(e) {
console.log('Server emitted ping: ' + e.data);
mSocket.emit('pong', 'hi server!');
});
}
}
~(function onLoadSocketTimeout() {
var nextTimeout;
if (trialsToLoadSocketIo < 10) {
nextTimeout = 5000;
} else if (trialsToLoadSocketIo > 60) {
nextTimeout = 60000;
} else {
nextTimeout = 1000 * trialsToLoadSocketIo;
}
if (socketIoScript) {
document.head.removeChild(socketIoScript);
}
loadSocketIo(APP_CFG.baseUrl + '/socket.io/socket.io.js#' + trialsToLoadSocketIo);
loadSocketTimeout = $timeout(onLoadSocketTimeout, nextTimeout);
trialsToLoadSocketIo += 1;
})();
(I'm doing like this because it's mobile app so it may have not connection). I'm testing it with Brackets and Chrome. Server and client are in the same machine. In the app the script is loaded fine and it connects to the server as I can it see in node log (edit: and this is all what I get in the node console):
Server main is listening on port 2080
************************************************************
middleware!
connected...
Saying hello
Edit: in Chrome console I don't get any message, and any breakpoint stops at on listeners. If I stop node, the console for the Chrome immediately starts logging that it has been disconnected:
GET http://192.168.1.13:2080/socket.io/?EIO=3&transport=polling&t=1413066902601-6 net::ERR_CONNECTION_REFUSED
GET http://192.168.1.13:2080/socket.io/?EIO=3&transport=polling&t=1413066906606-7 net::ERR_CONNECTION_REFUSED
But I can't see any incoming message. In the app I don't receive any incoming message. Is there any reason why I could not communicate in this environment even if socket is successfully connected?
EDIT
No app is receiving events sent from the other side. Logs from node show this, logs from Chrome are empty.
EDIT
In Chrome app I don't receive console.log("Connected!");. But neither I receive ERR_CONNECTION_REFUSED errors: I don't receive anything.
EDIT
I managed to get console.log("Connected!"); in the app by changing Manager options:
mIoSocket = new io.Manager(APP_CFG.baseUrl, { autoConnect: false });
As it was auto connecting and the events were attached after connection was made, "Connected" was never reached. But I'm still not receiving any event in any app.
I had a similar issue were event callbacks on the server were not firing when emitting. My event names were ping and pong. As soon as I renamed these events everything worked.
I suspect the event names ping and pong are reserved by socket.io and so cannot be used.
Ok, so a few things :
First, var mSocket doesn't seem to be initialized, so it may be difficult for it to emit() anything (am I missing something?)
Second, when you do :
socket.on('pong', function (data) {
console.log(data.message);
});
the server expects to receive an object containing a message property, eg : data = {message:'hi server'} In your case, you send a string, so data is 'Hi server !' and your log will say 'undefined'. You should change this bit to :
socket.on('pong', function (data) {
console.log(data);
});
and you have a similar problem the other way around, you send an object : { message: 'Hello from server ' + Date.now() }, and are trying to log a data property which does not exist. Change this bit to :
console.log('Server emitted ping: ' + e.message);
And third , you have to listen for events on the socket, not the 'manager'
Client :
mIoSocket.connect(function(socket) {
console.log('Connected!!');
socket.emit('pong');
socket.on('error', function onSocketError(e) {
console.log('WebSocket Error ' + error);
});
socket.on('ping', function onPingReceived(e) {
console.log('Server emitted ping: ' + e.data);
socket.emit('pong', 'hi server!');
});
});
Server :
io.on('connection', function (socket) {
console.log('connected...');
socket.on('pong', function (data) {
console.log(data);
});
setTimeout(function() {
console.log("Saying hello");
socket.emit('ping', { message: 'Hello from server ' + Date.now() });
}, 1000);
});

Node.js: client doesn't die when TCP connection closes

I built a simple TCP server and a simple TCP client in Node.js
Now, when the client sends "exit" to the server, the connection is successfully closed. The server deletes the socket from its sockets list and sends "Bye bye!" to the client.
The connection on the client is closed as well but the app is still waiting for other inputs, so it doesn't die and I'm forced to type CTRL+C.
I tried adding process.exit() after connection closes but it doesn't work:
CLIENT CODE:
var net = require('net'),
config = require(__dirname + '/config.json'),
connection = net.createConnection(config.port, config.host);
connection.setEncoding('utf8');
connection.on('connect', function () {
console.log('Connected');
});
connection.on('error', function (err) {
console.error(err);
});
connection.on('data', function (data) {
console.log('» ' + data);
});
connection.on('close', function() {
console.log('Connection closed');
});
process.stdin.on('data', function (data) {
if ((new String(data)).toLowerCase() === 'exit') {
connection.end();
process.exit();
}
else {
connection.write(data);
}
});
process.stdin.resume();
SERVER CODE:
var server = require('net').createServer(),
config = require(__dirname + '/config.json'),
sockets = [];
server.on('connection', function (socket) {
socket.setEncoding('UTF-8');
socket.on('data', function (data) {
console.log('Received data: ' + data);
if (data.trim().toLowerCase() === 'exit') {
socket.write("Bye bye!\n");
socket.end();
}
else {
sockets.forEach(function (client) {
if (client && client != socket) {
client.write(data);
}
});
}
});
socket.on('close', function () {
console.log('Connection closed');
sockets.splice(sockets.indexOf(socket), 1);
console.info('Sockets connected: ' + sockets.length);
});
sockets.push(socket);
});
server.on('listening', function () {
console.log('Server listening');
});
server.on('close', function () {
console.log('Server is now closed');
});
server.on('error', function (err) {
console.log('error:', err);
});
server.listen(config.port);
EDIT:
I added a client connection "on close" event handler. So, the string "Connection closed" is now printed by the server and by the client too.
I think you're looking for this: socket.unref().
From Node.js documentation (https://nodejs.org/api/net.html#net_socket_unref):
socket.unref()#
Calling unref on a socket will allow the program to exit if this is the only active socket in the event system. If the socket is already unrefd calling unref again will have no effect.
Some time ago when improving the tests suite for node-cubrid module, I had encountered the same problem. After all tests have passed, nodeunit process didn't quit because node-cubrid was using connection.end() to close the client socket when timeout occurs, just like you did.
Then I replaced connection.end() with connection.destroy(), a cleaner way to ensure the socket is really closed without actually terminating the running process, which, I think, is a better solution than the above suggested process.exit(). So, in your client code context, I would do:
process.stdin.on('data', function (data) {
if ((new String(data)).toLowerCase() === 'exit') {
connection.destroy();
}
else {
connection.write(data);
}
});
According to Node.js documentation:
socket.destroy()
Ensures that no more I/O activity happens on this socket. Only necessary in case of errors (parse error or so).
I doubt that if ((new String(data)).toLowerCase() === 'exit') is succeeding because data most likely has a trailing newline (in your server, you trim() before doing the comparison, but not in the client).
If that's fixed, you've got a logic problem: when getting "exit" you close the connection without sending "exit" to the server, so the server code that looks for "exit" will never execute.
You have to put the process.exit() instruction only on the last event handler. So, in this case you have to put it inside the client connection "on close" event handler:
CLIENT:
connection.on('close', function() {
console.log('Connection closed');
process.exit();
});
Try with Event: 'close' in the server:
http://nodejs.org/api/net.html#net_event_close

Resources