Node.js tcp socket shut off trigger - javascript

I use node.js with the NET class to connect multiple Rasperry Pi's.
//Server
const net = require('node:net');
const server = net.createServer();
//Client
const tcpConnect = net.createConnection(SERVERINFO);
Thereby I can easily register multiple clients, open/close streams. Everything works without any problems.
But now I noticed that the callbacks.
tcpConnect.on('end', () => { console.log('end triggered') });
tcpConnect.on('close', () => { console.log('close triggered') });
tcpConnect.on('error', () => { console.log('error triggered') });
do not work if the server suddenly has a power failure (e.g. power supply is pulled). The clients don't trigger an error/end or close, so I can't close the connection properly.
As a result, an error is not triggered until the next attempt to write something to an existing stream. But this is not an option for me, especially for "online monitoring".
Does anyone know a way to identify the shut off of the server immediately?

You need to enable TCP keep-alives in order for the client to detect that the server is no longer responding and you can tune how often it checks on an idle connection. (I've written a language generic description at the beginning of this answer.)
In node it appears you can do this: socket.setKeepAlive(true), i.e. for this client to detect the server is gone when the socket is idle:
//Client
const tcpConnect = net.createConnection(SERVERINFO);
tcpConnect.setKeepAlive(true);

Related

multiple browser instances with websocket capabilities in node?

Let's say I am building a social app. I want to log into multiple accounts (one per browser instance) without an user interface (all via node), and by calling all respective endpoints to log in and start chatting.
The important part is to test when an user closed the tab or logs out or leaves the group and therefore the websocket's connection closes.
If I understand you correctly.
You would like to make a server-side event happen whenever a client connects or disconnects, without any html,css.... or any other user interface.
You can do it like this in node :
For connection you use :
Server.on("connection,function(ws){some stuff...})
The function that is called on connection will get the websocket that connected as parameter by default. I just use a lambda function here you can also call one that will then get the websocket as parameter.
For disconnection you put a function in the Server.on function to monitor when the client disconnected. Like this :
Server.on("connection,function(ws){
ws.onclose = function (ws) {
some stuff...
}
})
You can again replace the lambda function by another one.
Server is in my case equal to this :
const wsserver = require("ws").Server
const server = new wsserver({ port: someport })
But it can vary.
All you need to do apart from that is connect the client.
I do it like this but it can vary as well.
const ws = new WebSocket("ws://localhost:someport");
I hope this is helpful.

Unable to get Notify data using Noble

Can't receive any notifications sent from the Server peripheral.
I am using ESP32 as Server with the "BLE_notify" code that you can find in the Arduino app (File> Examples ESP32 BLE Arduino > BLE_notify).
With this code the ESP32 starts notifying new messages every second once a Client connects.
The client used is a Raspberry Pi with Noble node library installed on it (https://github.com/abandonware/noble). this is the code I am using.
noble.on('discover', async (peripheral) => {
console.log('found peripheral:', peripheral.advertisement);
await noble.stopScanningAsync();
await peripheral.connectAsync();
console.log("Connected")
try {
const services = await peripheral.discoverServicesAsync([SERVICE_UUID]);
const characteristics = await services[0].discoverCharacteristicsAsync([CHARACTERISTIC_UUID])
const ch = characteristics[0]
ch.on('read', function(data, isNotification) {
console.log(isNotification)
console.log('Temperature Value: ', data.readUInt8(0));
})
ch.on('data', function(data, isNotification) {
console.log(isNotification)
console.log('Temperature Value: ', data.readUInt8(0));
})
ch.notify(true, function(error) {
console.log(error)
console.log('temperature notification on');
})
} catch (e) {
// handle error
console.log("ERROR: ",e)
}
});
SERVICE_UUID and CHARACTERISTIC_UUID are obviously the UUIDs coded in the ESP32.
This code sort of works, it can find Services and Characteristics and it can successfully connect to the peripheral, but it cannot receive messages notifications.
I also tried an Android app that works as client, from that app I can get all the messages notified by the peripheral once connected to it. So there is something missing in the noBLE client side.
I think there is something wrong in the on.read/on.data/notify(true) callback methods. Maybe these are not the methods to receive notifications from Server?
I also tried the subscribe methods but still not working.
The official documentation is not clear. Anyone could get it up and running? Please help.
on.read/on.data/ are event listeners. There is nothing wrong with them. They are invoked when there is a certain event.
For example adding characteristic.read([callback(error, data)]); would have invoked the on.read.
From the source:
Emitted when:
Characteristic read has completed, result of characteristic.read(...)
Characteristic value has been updated by peripheral via notification or indication, after having been enabled with
characteristic.notify(true[, callback(error)])
I resolve using the following two envs NOBLE_MULTI_ROLE=1 and NOBLE_REPORT_ALL_HCI_EVENTS=1 (see the documentation https://github.com/abandonware/noble)

How to create sockets that particular to user and disposable on Socket.Io

I write a Node.Js app and I use Socket.Io as the data transfer system, so requests should be particular to per user. How can I make this?
My actual code;
node:
io.on('connection', (socket) => {
socket.on('loginP', data => {
console.log(data);
})
})
js:
var socket = io('',{forceNew : false});
$("#loginbutton").click(function() {
var sessionInfo = {
name : $("#login input[name='username']").val(),
pass : $("#login input[name='pass']").val()
}
socket.emit("loginP", sessionInfo)
})
It returns one more data for per request and this is a problem for me. Can I make this on Socket.Io or should I use another module, and If I should, which module?
If I understand your question correctly (It's possible I don't), you want to have just one connection from each user's browser to your nodejs program.
On the nodejs side, your io.on('connection'...) event fires with each new incoming user connection, and gives you the socket for that specific connection. So, keep track of your sockets; you'll have one socket per user.
On the browser side, you should build your code to ensure it only calls
var socket = io(path, ...);
once for each path (your path is ''). TheforceNew option is for situations where you have multiple paths from one program.

Browser connecting with multiple sockets using JS socket.io

I'm using node.js with a React front end. I'm building a GPS based MMO type of game. I recently decided to drop most HTTP requests and go with sockets, so I can emit data whenever I want and the front end only has to worry about what to do with it when it receives it.
I've built sites with sockets before, but never ran into this issue.
Basically, every time my browser opens a socket connection with node, it opens 2-3 connections at once(?). When it disconnects, I get the console.log stating that 3 socket connectionss have been closed. It'll look like this:
User disconnected
User disconnected
A user has connected to the system with id: nUMbkgX6gleq-JZQAAAD
A user has connected to the system with id: CzFtR2K5NJ1SoiHLAAAE
A user has connected to the system with id: tgGYhpXuOONmL0rMAAAF
For now, it wouldn't be an issue, however I'm only getting the FIRST 'inventory' emit to work. Later when I call the function to emit inventory again, the browser doesn't seem to get it. But the console logs in the node function will trigger correctly.
I have a feeling that this has something to do with multiple sockets opening.
Here is the React Event:
this.socket.on("inventory", charData => {
console.log('heres the data', charData)
props.setCharStats(charData[0])
})
Here's the node emitter:
const getCharInventory = (charId, userId) => {
dbInstance
.getCharInventory(charId)
.then(response => {
console.log( // this console.log happens just fine
"emmited inventory, userId is: ", userId, " with this response: ", response)
socket.emit("inventory", response)
})
.catch(err => console.error(err))
}
I'm such a dork. I was starting multiple connections within multiple connections.
In more than one component, I had this...
this.socket = socketIOClient(`${process.env.REACT_APP_proxy}`)
Sooo..... yeah. Just an FYI to others, it's better to connect in 1 file and import it into others.

How can I connect a node.js server page to my sockets server as though it were a client?

I've seen many similar questions here, like this one about connecting servers to sockets, however, that doesn't seem to be working.
My goal is to have one of my server pages occasionally emit an "advance" event to all of the connected clients. My sockets server listener (sockets.js) looks like this
io.on('connection', function (socket) {
socket.on('advance', function () {
console.log('advancing clients');
io.emit('advance');
});
});
and my other server page (queue.js) has this code
var socket = require('socket.io-client');
socket.connect('localhost:5000');
socket.on('connect', function () {
socket.emit('advance');
});
I have also tried
var socket = require('socket.io-client');
socket.connect('localhost:5000');
socket.emit('advance');
Both of those were in the other question I linked, however both of those failed. In the case of the first example, I received the error
socket.on is not a function
and on the second
socket.emit is not a function
it would seem that socket.connect worked, however, socket.on and socket.emit both failed. The idea is that queue.js will emit an event to all the clients, so they know to request the next song from the server.
As bonus points, I happen to be using passport.socketio to authenticate my users (though I don't seem to be getting the "ioAuthFail" message that would normally occur when a user attempts to connect and is not authenticated).
for what it's worth, my socket authentication code looks like
io.use(passportSocketIo.authorize({
//cookieParser:
key:'user',
secret:'secret',
store:new MongoStore({mongooseConnection:mongoose.connection}),
success:onAuthorizeSuccess,
fail:function(){console.log('ioAuthFail')}
}));
If there's a better way to advance the clients than using socket.io, i would also accept that, but for now it seems like this is the best way for me, assuming I can get this working.
EDIT
as mentioned through comments, changing my code to
var io = require('socket.io-client');
socket = io.connect('localhost:5000');
socket.on('connect', function () {
socket.emit('advance');
});
socket.emit('advance');
doesn't break it, but it doesn't work, either.

Categories