I have module which executes a shell command when user clicks submit on the UI,but the problem here is that at the time of clicking submit command:
number of times command executed= number of tabs that this UI is being opened while clicking submit button
Server side code:
const wsServer = new WebSocket.Server({
noServer: true,
});
wsServer.on("connection", function (ws) {
ws.on("message", function (msg) {
wsServer.clients.forEach(function each(client) {
if (client.readyState === WebSocket.OPEN) {
var coffeeProcess = exec(msg.toString());
coffeeProcess.stdout.on("data", function (data) {
console.log(data);
client.send(data);
});
}
});
});
});
myServer.on("upgrade", async function upgrade(request, socket, head) {
//handling upgrade(http to websocekt) event
//emit connection when request accepted
wsServer.handleUpgrade(request, socket, head, function done(ws) {
wsServer.emit("connection", ws, request);
});
});
Client side code:
//Creating DOM element to show received messages on browser page
function msgGeneration(msg, from) {
console.log("msg:" + msg + "-from:" + from);
}
//enabling send message when connection is open
mywsServer.onopen = function () {
console.log("Socket Connection Established");
};
//handling message event
mywsServer.onmessage = function (event) {
const { data } = event;
console.log("Message Event", data);
results.push(data);
result.innerText+=results.slice(-1)[0]
};
Hiding the details that has info here in the client side
I am very new to this :
I learned javascript sessions would be helpful here
Related
Hey super new to socket io and web sockets in general. I have a chatting app scenario with socket io where client emits to the server and the server emits back to the client.
In my case the emits from the client side are picked up on the server side so far no problems.
However on the client side there are some socket.on statements there to pick up stuff from the server. A generic console.log after connection fires, but the other socket.on statements do not.
My thought was that maybe the server side emits aren't firing. Where it gets weird though is that when I change something in the client side file with the socket.on statements, the client side statements will pick up the emits from the server until the next time I refresh the page.
It is also work noting that these client on statements work with the info that was gathered before the save: if something is like
Client-side:
socket.on("message", (data) => {
console.log(foo)
});
and I change it to
socket.on("message", (data) => {
console.log(bar)
});
and then trigger the chain of emits,
the socket.on("message... will fire properly but it will log "foo". My guess is that saving the client side socket file is creating a new connection or something, but I'm curious as to why only the old connection is picking up things from the server and not the new one?
My code for reference:
(client)
const token = localStorage.getItem("messenger-token");
const socket = io.connect('http://localhost:3001', {
query: {token}
});
//const socket = io('http://localhost:3001');
socket.on("connect", () => {
console.log("connected to server");
socket.on("new-message", (data) => {
console.log(data.message)
store.dispatch(setNewMessage(data.message, data.sender));
});
socket.on("mark-as-read", (data) => {
store.dispatch(markedAsRead(data.convoToUpdate,'socket'));
});
});
(server)
//www
const server = http.createServer(app);
app.io.attach(server,{'pingInterval': 2000, 'pingTimeout': 50000});
//app
app.io = require('socket.io')();
require('./sockets')(app)
app.io.use(function(socket, next){
const token = socket.handshake.query.token
if (token) {
jwt.verify(token, process.env.SESSION_SECRET, (err, decoded) => {
if (err) {
return next(new Error('Authentication error'));
}
User.findOne({
where: { id: decoded.id },
}).then((user) => {
return next();
});
});
} else {
return next();
}
})
//sockets module
module.exports = (app) => {
app.io.on("connection", (socket) => {
console.log("connected")
socket.on("new-message", (data) => {
socket.broadcast.emit("new-message", {
message: data.message,
sender: data.sender,
});
socket.on("mark-as-read", (data) => {
socket.broadcast.emit("mark-as-read", {
convoToUpdate:data.convoId
});
});
});
I don't know if this is appropriate but it turns out I didn't have a problem.
the server logic:
socket.broadcast.emit("mark-as-read", {
convoToUpdate:data.convoId
});
});
uses broadcast.emit instead of regular emit. This sends the new info to everyone except the sender as seen in the docs. oops
I have a Vue app that sets up a socket connection when the user logs in.
My component has a method that accesses an outer variable socket I made so that I can emit events in other methods..
onLoginSuccess() {
socket = io(`${process.env.SERVER_URL}`);
socket.emit('login', localStorage.getItem('username'));
socket.on('login-response', (response) => {
if (!response.status) {
alert(response.message);
return false;
} else {
this.$router.push("/home");
this.$refs.form.reset();
}
});
}
However, when I try to do socket.emit in another event it doesn't work:
onSocketLogout() {
console.log('socket logout call', socket)
socket.emit('delete_username_from_array', localStorage.getItem('username') );
},
Socket doesn't seem to be null/undefined on the console and I tried putting the same event emitter on the onLoginSuccess function and it works fine. It just doesn't work when I use socket in other functions or places outside the initial connection.
Here's my socket io server code:
let logged_in_users = [];
const io = require('socket.io')(http);
io.on('connection', function(socket){
console.log(`Socket ${socket.id} connected`);
socket.on('login', function(username){
// check duplicates
if(logged_in_users.includes(username)){
socket.emit('login-response', {
message: 'It seems that you have already logged in on another browser. Please logout first.',
status: false
});
return false;
}else{
socket.emit('login-response', {status: true});
console.log(`${username} logged in`)
logged_in_users.push({ username, id: socket.id });
}
});
// for logout
socket.on('delete_username_from_array', function(username){
console.log('removing username from array')
// delete the username from the array of logged in users
logged_in_users.splice( logged_in_users.indexOf(username), 1 );
});
socket.on('test', () => {
console.log("TEST")
})
socket.on('disconnect', () => {
console.log(`Socket ${socket.id} disconnected`);
console.log(logged_in_users)
})
});
I'm writing a ZooKeeper client to monitor a node. The callback function gets called only the first time I change the data of the node. I'm not sure why the function doesn't execute on the second change.
A second query is that my program terminates if I uncomment the last close() function. As a good practice, I should use the close() function but then it doesn't enter the blocking state to listen to the incoming events. How do I achieve it? I've read the documentation but couldn't find anything useful.
var zookeeper = require("node-zookeeper-client");
var client = zookeeper.createClient("192.168.43.172:2181");
var path = process.argv[2];
client.once("connected", function() {
console.log("Connected to the server.");
client.create(path, new Buffer("data"), function(error) {
if (error) {
console.log("Failed to create node: %s due to: %s.", path, error);
} else {
console.log("Node: %s is successfully created.", path);
}
});
client.getData(
path,
function(event) {
console.log("Got event: %s.", event);
},
function(error, data, stat) {
if (error) {
console.log(error.stack);
return;
}
console.log("Got data: %s", data.toString("utf8"));
}
);
//client.close();
});
client.connect();
I still don't have an answer to my second query but for the first query, the zookeeper server is designed to send an event only the first time a change takes place and then delete the switch. In order to keep receiving the events, I had to set a watch again while handling the triggered event. Below is my code:
var zookeeper = require("node-zookeeper-client");
var client = zookeeper.createClient("192.168.43.172:2181");
var path = process.argv[2];
client.once("connected", function() {
console.log("Connected to the server.");
var watch = function(event) {
console.log("Got event: %s.", event);
client.getData(path, watch, getDat);
};
var getDat = function(error, data, stat) {
if (error) {
console.log(error.stack);
return;
}
console.log("Got data: %s", data.toString("utf8"));
};
client.getData(path, watch, getDat);
// client.close();
});
client.connect();
I'm working on chat, where facebook friends can talk only with each other. I'm using redis so save relation: fb_user_id - user_socket_id. This is how my implementation looks like:
getting friends from facebook;
selecting socket ids of my friends from redis, creating local friends-sockets list in my node client;
connecting to node server. Server saving my socket id to redis and notifying all my friends about new friend login (about me);
all my friends updating local friends-sockets list;
when someone sending chat message to server, this message comes with friends-sockets list, so server knows where need to send message (only for my friends).
Question: it's better solution to send friends-sockets every time to server, or it's better to get this relation on server from redis (or create array of sockets in server). How to adapt my task for high availability?
Any comments and suggestions are welcomed, thanks.
Here is my code (socket.io 1.2.0)
server.js
var app = require('express')();
var http = require('http').Server(app);
var io = require('socket.io')(http);
var redis = require("redis"), client = redis.createClient();
var parts;
client.select(2, function() {});
client.on("error", function (err) {
console.log("Error " + err);
});
process.on('uncaughtException', function (err) {
console.log(err);
});
app.get('/', function (req, res) {
res.sendFile(__dirname + '/index.html');
});
io.on('connection', function (socket) {
// on connect
socket.on("join", function (data)
{
if (data) {
// notify all friedns about new friend login
if (data.to) {
if (data.to.length > 0) {
for (x in data.to) {
io.to(data.to[x]['socket_id']).emit('new friend response', {uid: data.uid, sid: socket.id});
}
}
}
// save or update user socket id to redis
parts = split_id(data.uid);
client.hset(parts[1], parts[0], socket.id);
}
});
// disconnect
socket.on('disconnect', function () {
console.log("user disconnected");
});
// send message by friends-sockets list
socket.on('chat message', function (data) {
if (data.to.length > 0) {
for (x in data.to) {
var message = data.msg;
io.to(data.to[x]['socket_id']).emit('chat message response', {msg: message, uid: data.uid});
}
}
});
});
http.listen(3000, function () {
console.log('listening on *:3000');
});
// split facebook uid in 2 parts (for redis saving)
function split_id(str)
{
var n = str.length;
var res1 = str.substr(n - 2, 2);
var res2 = str.substr(0, n - 2);
return [res1, res2];
}
client.js
// friends socket list
var friends_sockets = [];
// my data from facebook
var my_data;
// my facebook uid
var my_uid;
function client() {
socket = io('http://server.com:3000');
// connect
socket.on('connect', function () {
// notify server about login
socket.emit('join', {uid: my_uid, to: friends_sockets, from: my_data, type: 'web'});
});
// send chat message to my friends
$('.enter_form button').click(function () {
if (friends_sockets.length > 0) {
socket.emit('chat message', {msg: $('#m').val(), to: friends_sockets, from: my_data, uid: my_uid});
}
// add message to my chat
$('#messages').append($('<li>').text(my_data.first_name + ' ' + my_data.last_name + ': ' + $('#m').val()));
$('#m').val('');
return false;
});
// new message listner (waiting for chat messages)
socket.on('chat message response', function (data) {
$('#messages').append($('<li>').text(data.msg));
});
// new friends lister (update list on friends login)
socket.on('new friend response', function (data) {
var found = false;
if (friends_sockets.length > 0) {
for (x in friends_sockets) {
if (friends_sockets[x]['uid'] == data.uid) {
friends_sockets[x]['socket_id'] = data.sid;
found = true;
}
}
}
if (found === false) {
friends_sockets.push(data);
}
});
}
Concerning your question regarding high availablity, have a look at
http://socket.io/docs/using-multiple-nodes/
for a configuration example using nginx, multiple Node processes and Redis as session store.
I am new to node.js and would like to connect to a TCP socket. For this I am using the net module.
My idea was to wrap the connect sequence into a function then on the 'close' event, attempt a reconnection. Not that easy apparently.
function conn() {
client.connect(HOST_PORT, HOST_IP, function() {
startSequence();
})
}
client.on('close', function(e) {
log('info','Connection closed! -> ' + e)
client.destroy();
setTimeout(conn(),1000);
});
So when the remote host is closed, I see my logs comming through, howere what seems to be happening is that as soons as the remote host comes online ALL the previous attempts start to get processed - if that makes sense. If you look at client.connect, there is a function called startSequence that sends some data that "iniates" the connection from the remote server side. When the server goes offline and I start reconnecting all the failed attempts from before seem to have been buffered and are all sent together when the server goes online.
I have tried the code from this Stackoverflow link as well to no avail (Nodejs - getting client socket to try again after 5 sec time out)
client.connect(HOST_PORT, HOST_IP, function() {
pmsStartSequence();
})
// Add a 'close' event handler for the client socket
client.on('close', function(e) {
log('debug','connection closed -> ' + e)
client.setTimeout(10000, function() {
log('debug', 'trying to reconnect')
client.connect(HOST_PORT, HOST_IP, function() {
pmsStartSequence();
})
})
});
Is there any advice on how I can reconnect a socket after failure?
Inspired from the other solutions, I wrote this, it's tested, it works !
It will keep on trying every 5 sec, until connection is made, works if it looses connection too.
/* Client connection */
/* --------------------------------------------------------------------------------- */
const client = new net.Socket()
var intervalConnect = false;
function connect() {
client.connect({
port: 1338,
host: '127.0.0.1'
})
}
function launchIntervalConnect() {
if(false != intervalConnect) return
intervalConnect = setInterval(connect, 5000)
}
function clearIntervalConnect() {
if(false == intervalConnect) return
clearInterval(intervalConnect)
intervalConnect = false
}
client.on('connect', () => {
clearIntervalConnect()
logger('connected to server', 'TCP')
client.write('CLIENT connected');
})
client.on('error', (err) => {
logger(err.code, 'TCP ERROR')
launchIntervalConnect()
})
client.on('close', launchIntervalConnect)
client.on('end', launchIntervalConnect)
connect()
The problem is where you set the on-connect callback.
The doc of socket.connect() says:
connectListener ... will be added as a listener for the 'connect' event once.
By setting it in socket.connect() calls, every time you try reconnecting, one more listener (a one-time one), which calls startSequence(), is attached to that socket. Those listeners will not be fired until reconnection successes, so you got all of them triggered at the same time on a single connect.
One possible solution is separating the connect listener from socket.connect() calls.
client.on('connect', function() {
pmsStartSequence();
});
client.on('close', function(e) {
client.setTimeout(10000, function() {
client.connect(HOST_PORT, HOST_IP);
})
});
client.connect(HOST_PORT, HOST_IP);
My solution:
var parentHOST = '192.168.2.66';
var parentPORT = 9735;
var net = require('net');
var S = require('string');
var parentClient = new net.Socket();
var parentActive = false;
var startParentClient = function () {
parentClient = new net.Socket();
parentActive = false;
parentClient.connect(parentPORT, parentHOST, function() {
console.log('Connected ' + cluster.worker.id + ' to parent server: ' + parentHOST + ':' + parentPORT);
parentActive = true;
});
parentClient.on('error', function() {
parentActive = false;
console.log('Parent connection error');
});
parentClient.on('close', function() {
parentActive = false;
console.log('parent connection closed');
setTimeout(startParentClient(), 4000);
});
}
If is necessary connect:
if (!S(parentHOST).isEmpty() && !S(parentPORT).isEmpty()) {
startParentClient();
}
As mentioned multiple times in the comments, you need to use .removeAllListeners() before trying to reconnect your client to the server in order to avoid having multiple listeners on the same event.
The code below should do the trick
Note that I try to reconnect the client after the close and end events because these two events can be fired in different orders after closing a connection
const net = require("net")
let client = new net.Socket()
function connect() {
console.log("new client")
client.connect(
1337,
"127.0.0.1",
() => {
console.log("Connected")
client.write("Hello, server! Love, Client.")
}
)
client.on("data", data => {
console.log("Received: " + data)
})
client.on("close", () => {
console.log("Connection closed")
reconnect()
})
client.on("end", () => {
console.log("Connection ended")
reconnect()
})
client.on("error", console.error)
}
// function that reconnect the client to the server
reconnect = () => {
setTimeout(() => {
client.removeAllListeners() // the important line that enables you to reopen a connection
connect()
}, 1000)
}
connect()
I use the following code to achieve reconnection with node.js. I am not a Javascript expert so I guess it can be improved but it nevertheless works fine for me.
I hope this could help.
Best.
//----------------------------------------------------------------//
// SocketClient //
//----------------------------------------------------------------//
var net = require('net');
var SocketClient = function(host, port, data_handler, attempt)
{
var node_client;
var attempt_index = (attempt ? attempt : 1);
this.m_node_client = new net.Socket();
node_client = this.m_node_client;
this.m_node_client.on('close', function()
{
var new_wrapper = new SocketClient(host, port, data_handler, attempt_index + 1);
node_client.destroy();
new_wrapper.start();
});
this.m_node_client.on('data', data_handler);
this.m_node_client.on('error', function(data)
{
console.log("Error");
});
this.start = function()
{
this.m_node_client.connect(port, host, function()
{
console.log('Connected ' + attempt_index);
});
};
};
//----------------------------------------------------------------//
// Test //
//----------------------------------------------------------------//
var test_handler = function(data)
{
console.log('TestHandler[' + data + ']');
};
var wrapper = new SocketClient('127.0.0.1', 4000, test_handler);
wrapper.start();
I have tried re-using the same socket connection, by using this:
const s = net.createConnection({port});
s.once('end', () => {
s.connect({port}, () => {
});
});
that didn't work, from the server-side's perspective. If the client connection closes, it seems like a best practice to create a new connection:
const s = net.createConnection({port});
s.once('end', () => {
// create a new connection here
s = net.createConnection(...);
});
sad but true lulz.
Following this:
//
// Simple example of using net.Socket but here we capture the
// right events and attempt to re-establish the connection when
// is is closed either because of an error establishing a
// connection or when the server closes the connection.
//
// Requires
const net = require('net');
// Create socket
const port = 5555;
const host = '127.0.0.1';
const timeout = 1000;
let retrying = false;
// Functions to handle socket events
function makeConnection () {
socket.connect(port, host);
}
function connectEventHandler() {
console.log('connected');
retrying = false;
}
function dataEventHandler() {
console.log('data');
}
function endEventHandler() {
// console.log('end');
}
function timeoutEventHandler() {
// console.log('timeout');
}
function drainEventHandler() {
// console.log('drain');
}
function errorEventHandler() {
// console.log('error');
}
function closeEventHandler () {
// console.log('close');
if (!retrying) {
retrying = true;
console.log('Reconnecting...');
}
setTimeout(makeConnection, timeout);
}
// Create socket and bind callbacks
let socket = new net.Socket();
socket.on('connect', connectEventHandler);
socket.on('data', dataEventHandler);
socket.on('end', endEventHandler);
socket.on('timeout', timeoutEventHandler);
socket.on('drain', drainEventHandler);
socket.on('error', errorEventHandler);
socket.on('close', closeEventHandler);
// Connect
console.log('Connecting to ' + host + ':' + port + '...');
makeConnection();
function createServer() {
const client = new net.Socket();
client.connect(HOST_PORT, HOST_IP, function() {
console.log("Connected");
state = 1 - state;
client.write(state.toString());
});
client.on("data", function(data) {
console.log("Received: " + data);
//client.destroy(); // kill client after server's response
});
client.on("close", function() {
console.log("Connection closed");
//client.connect()
setTimeout(createServer, 2000);
});
}
createServer();