I have a nodejs websocket server and need to send data from my serial port to the client every time it send data to me.
This is my ws on connection
wss.on('connection', ws => {
ws.on('message', message => {
console.log(`Received message => ${message}`)
})
ws.send('ho!')
})
This is my serial on Data
parser.on('data', (dados) => {
console.log(dados.toString('utf8'));
})
Basically, when the serial send me some data, i need to send it to the client.
Is there any way of making that trick? i thought that i could have some global variable and make it as a bridge between both actions.
i.e: Whenever serial send me some data i put it on my variable and each 2 seconds my ws server sends whatever is in that variable to the client.
Inside your 'data' callback, instead of the line of console.log(dados.toString('utf8'));
you can put the below code:
wss.clients.forEach(function each(client) {
if (client.readyState === WebSocket.OPEN) {
client.send(dados.toString('utf8'));
}
});
the collection wss.clients should contain only one ws client as i understand, based on your architecture.
Related
I have a front end client, which is written in VueJs and a Backend API which is written in Node Js. The Node API communicates with other third party APIs and in turn sent responses back to the client. Now for some of the APIs, it is taking a long time, more than a minute to complete the request and send the response back to the client. As the Node App is proxied over Akamai, it sends a 503 error after a certain time and thus and error will be thrown to the enduser. But the actual process that the third party API do is still in progress and it will send a success response back to the Node App once it is completed. As the client already received the error, it will not receive the success message.
I have this issue with the account creation flow. The client form data is posted to NodeJS backend, which eventually post to another third party API. While waiting for the call to finish, the Akamai proxy will send 503 HTTPS status with Zero Size object response. Client receives this error message and a custom error will be shown. But the account is being created in the backend and eventually it will send success response to the node app, but this never reaches the client and so the user. There is a chance that user will create another account.
The front end call is as follows:
return new Promise((resolve, reject) => {
const config = {}
config.method = 'POST'
config.url = APIaddress
config.data = data
config.params = params
config.withCredentials = true
config.httpsAgent = new https.Agent({ keepAlive: true })
console.log('Config: ', config)
axios(config).then(response => {
console.log('RESPONSE: ', response)
resolve(response)
}).catch(error => {
console.log('ERROR: ', error.response)
reject(error.response.data)
})
})
Here I added the KeepAlive option, but it has no effect and I still get the error.
Now, in the backend also, I use agentkeepalive, and the call is as follows:
const HttpsAgent = agentkeepalive.HttpsAgent
const keepaliveAgent = new HttpsAgent({
timeout:120000,
freeSocketTimeout:60000
});
const options = {
method: 'POST',
url: config.endpoint.url,
headers:
{
'Content-Type': 'application/json;charset=utf-8',
'Accept': 'application/json',
authorization: 'Bearer ' + token
},
data: data,
json: true,
httpsAgent:keepaliveAgent
};
axios(options)
.then(response => response.data)
.then(response => {
resolve(response)
})
.catch(function (error) {
logger.error({
message: `Error while creating account: ${error}`
});
reject(error);
});
Now in order to account for the delays, I am planning to use Server Side Events or WebSockets. I am very new to this and not sure which one to use. I think by using one of these, I can send response back to the client once the account is created. Currently the client is waiting for the account to be created, but I want to make it in such a way that client will send the initial requests and then the server will send notification to the client, once the account is created. This will avoid the unnecessary timeouts and other related issues.
I not sure which solution has to be used here. It will be helpful if someone can shed some light. Thanks for reading.
I switched from SSE and RestAPI to WebSocket on my Node and React app. My setup is as follows:
Create WebSocket server in Node
Create connection from client to server
Then I use "publish-subscribe" pattern.
When client needs something from server, it sends WebSocket message to server with specific sign (In my case it is called "route".) Server filters the message and sends it to proper router (not the Express one, these are routes in my server handling the WebSocket requests.)
As it is processed, server sends WebSocket message back to client, which filters it and processes.
This allows me to have always opened connection to server, what is very swift, and - that's what you are looking for - wait for some message from server without blocking the connection or risking timeout.
Very simple code example:
server:
ws.on('message', m => {
if (m.route === DO_SOMETHING) {
...do something...
ws.send(JSON.stringify({route: DO_SOMETHING_RESPONSE}, message: 'Something was
done'})
}
)
client:
// I want something to be done from server:
ws.send(JSON.stringify({route: DO_SOMETHING, message: 'something should be done'}))
// this is send and you can wait a year for a response, which is catched with:
ws.on('message', m => {
if (m.route === DO_SOMETHING_RESPONSE) {
console.log('Yupeee, something was done!')
}
)
This way you can handle unlimited number of requests. You can make them independent as in this example. Or you can force client to wait for the answger from server.
I have a connection with the server and client and have the server listening for a player to be made in the lobby. The server receives the player name and updates the player, however, when emitting the player back to the client I am having issues.
Simply, the pseudo-structure of our implementation follows as such...
Server
io.on('connection', function(socket){ ....
socket.emit('ack', {....
socket.on('createPlayer', function(data){
.... (update newPlayer object) .....
socket.emit('newPlayer', {
playerName: newPlayer.name
[...]
Client
let socket = io();
socket.on('ack', function(data) {
console.log('ack', data)
}
socket.on('newPlayer', function(data) {
console.log('newPlayer', data)
When a connection is made by the client's browser to the server, the 'ack' message is sent and received and logged to the client's console. But, When the client makes a new player and the 'createPlayer' socket.on is hit it tries to emit the new player back to the client but is never received.
Any suggestions as to why the client would never receive the sent message?
You should use this for sending message to all connected clients:
io.emit('event_name', msg);
Also you should use this for all clients except new clients:
socket.broadcast.emit('event_name', msg);
This function is for sending message to new client that sent message at that time:
socket.emit('event_name', msg)
You can send specified client using this method:
io.to(socketId).emit('event_name', data)
I've written the following function:
let responses = {}
let socks = {}
module.ping = function (port, address) {
//console.log(`Ping function was called - ${address} ${port}`)
if (socks[`${address}:${port}`]) {
//console.log("Using existing socket")
responses[`${address}:${port}`] = false
sock = socks[`${address}:${port}`]
sock.write('PING\n')
console.log(`Sent PING to ${address} ${port}`)
}
else {
sock = new net.Socket();
responses[`${address}:${port}`] = false
sock.connect(port, address, async function() {
sock.write('PING\n')
console.log(`Sent PING to ${address} ${port}`)
});
// Response listeners
sock.on('data', function(data) {
clean_data = data.toString().replace(/\n/g, '').replace(/\r/g, '')
console.log(`[${sock.remoteAddress}:${sock.remotePort}] Received ${clean_data}`)
if (clean_data == 'PONG') {
//console.log(`[${sock.remoteAddress}:${sock.remotePort}] Received PONG`)
//sock.end()
//delete socks[`${address}:${port}`]
responses[`${sock.remoteAddress}:${sock.remotePort}`] = true
}
}
});
sock.on('error', function(error) {
if (sock.remoteAddress) {
responses[`${sock.remoteAddress}:${sock.remotePort}`] = false
}
sock.destroy()
delete socks[`${address}:${port}`]
});
// Add to list of sockets
if (sock) {
socks[`${address}:${port}`] = sock
}
}
}
On the other end, I have a listening TCP server that simple responds with "PONG\n". When I try a single host I get the expected output:
module.ping(1337, 10.0.0.100)
await delay(5000) // Custom function
module.ping(1337, 10.0.0.100)
Sent PING to 10.0.0.100 1337
[10.0.0.100:1337] Received PONG
Sent PING to 10.0.0.100 1337
[10.0.0.100:1337] Received PONG
However when I attempt to hit multiple hosts:
module.ping(1337, 10.0.0.100)
module.ping(1337, 10.0.0.200)
await delay(5000) // Custom function
module.ping(1337, 10.0.0.100)
module.ping(1337, 10.0.0.200)
Sent PING to 10.0.0.100 1337
Sent PING to 10.0.0.200 1337
[10.0.0.200:1337] Received PONG
[10.0.0.200:1337] Received PONG
Sent PING to 10.0.0.100 1337
Sent PING to 10.0.0.200 1337
[10.0.0.200:1337] Received PONG
[10.0.0.200:1337] Received PONG
It seems to me that the event listener for "data" I've added has somehow bound to the incorrect address within my code, however I can't see where. If I add more hosts to the list, the last host with the PING sent is the one that all the PONGs are marked as part of.
For starters, I see no declaration for the sock variable which means it's in some some higher scope and getting wrongly confused or trounced between different asynchronous operations that are both in progress.
Declare that variable locally so each use of it is a separate variable and one async operation won't overwrite the one you were using for another operation. ALL variables, not purposely intended to be higher scoped and shared MUST be declared locally.
I don't know if that is the only problem here, but it IS a problem here. For example, if you call .ping() twice in a row and have to create two new sockets, the second one will overwrite the sock variable before the .connect() succeeds causing you to send the PING to the wrong sock which is exactly what your diagnostic logs show.
I have an angular application needing to subscribe to a websocket for incoming data.
On the angular side, in a service I have
setContextChannel(channel) {
this.contextWS = new WebSocket(channel);
that = this;
this.contextWS.onmessage = function(event) {
console.log('ws', event.data);
that.patientID = event.data;
};
this.contextWS.onerror = function(event) {
console.log('ws error', event);
}
}
and on the mock server side, I have a typescript node server that creates the socket as follows:
import {Server} from "ws";
var wsServer: Server = new Server({port: 8085});
console.log('ws on 8085');
wsServer.on('connection',websocket => websocket.send('first pushed message'));//////
my question is how to use the wsServer to send messages?
I'm not sure what are you asking about. This line is correct:
wsServer.on('connection',websocket => websocket.send('first pushed message'));
If you want to keep sending messages to all connected clients, you need to either use the property wsServer.clients to send messages to each connected client, or store the references to each connected client (the websocket variable in your code) in an array and then send the messages to each client using forEach().
Take a look at this code sample: https://github.com/Farata/angular2typescript/blob/master/chapter8/http_websocket_samples/server/bids/bid-server.ts
I am trying to make a proxy between sockets and websockets. I receive requests on socket server and I want to proxy them to websocket clients, however websocket.ws.send appears to be undefined. What would be the correct way of doing this? How to call ws.send() from outside of the object?
var WebSocketServer = require('ws').Server,
wss = new WebSocketServer({port: 8001}),
var net = require('net')
websocket = wss.on('connection', function(ws) {
ws.on('message', function(message) {
console.log('received: %s', message);
});
ws.send("NEW USER JOINED");
});
var socketServer = net.createServer(function(socket) {
socket.on("data", function(data){
console.log("Received: "+data)
websocket.ws.send("Message")
});
});
socketServer.listen(1337, '127.0.0.1');
The problem you have is that ws is a single web socket for one connection. It is not a property on the websocket object, but an argument to a callback you define. Each time someone connects you will get a connection event which will execute your callback, allowing you to bind a function to that specific web socket for the message event.
You either need to store the ws object in a variable that the socket server can access or you could broadcast to all clients.
wss.clients.forEach(function each(client) {
client.send(data);
});
This will work fine if you only have one client, however if you have multiple connections to both the websocket and socket server then you need to use a method of identifying connections on both so that you can locate the websocket connection you need to send data to.