Whats the problem with the socketio connection? - node.js

Im having this alot of http petitions (6k INSIDE LAGGING) in 1-3 minutes in the console when i receive or send data to a socketio connection.
Im using node+express in the backend and vue on the front
Backend:
app.js
mongoose.connect('mongodb://localhost/app',{useNewUrlParser:true,useFindAndModify:false})
.then(result =>{
const server = app.listen(3000)
const io = require('./sockets/socket').init(server)
io.on('connection', socket =>{
// console.log('client connected')
})
if(result){console.log('express & mongo running');
}
})
.catch(error => console.log(error))
I created a io instance to use it on the routes
let io
module.exports = {
init: httpServer => {
io = require('socket.io')(httpServer)
return io;
},
getIo:()=>{
if(!io){
throw new Error('socket io not initialized')
}
return io;
}
}
Then, on the route, depending of the logic, the if,else choose what type socket response do
router.post('/post/voteup',checkAuthentication, async (req,res)=>{
//some logic
if(a.length <= 0){
io.getIo().emit('xxx', {action:'cleanAll'})
}
else if(b.length <= 0){
io.getIo().emit('xxx', {action:'cleanT',datoOne})
}
else{
io.getIo().emit('xxx', {action:'cleanX',dataTwo,dataOne,selected})
}
res.json({ serverResponse:'success'})
})
In the front (component) (activated with beforeUpdate life cycle hook)
getData(){
let socket = openSocket('http://localhost:3000')
socket.on('xxx', data => {
if(data.action === 'cleanX'){
if(this.selected === data.selected){
this.ddd = data.dataTwo
}
else if(!this.userTeamNickname){
this.qqq= data.dataOne
}
}
else if(data.action === 'cleanAll'){
this.ddd= []
this.qqq= []
}
else if(data.action === 'cleanT'){
this.ddd= data.dataOne
}
})
},
1. What kind of behavior can produce this such error?
2. Is any other most efficient way to do this?

It looks like socket.io is failing to establish a webSocket connection and has never advanced out of polling. By default, a socket.io connection starts with http polling and after a bit of negotiation with the server, it attempts to establish a webSocket connection. If that succeeds, it stops doing the polling and uses only the webSocket connection. If the the webSocket connection fails, it just keeps doing the polling.
Here are some reasons that can happen:
You have a mismatched version of socket.io in client and server.
You have some piece of infrastructure (proxy, firewall, load balancer, etc...) in between client and server that is not letting webSocket connections through.
You've attached more than one socket.io server handler to the same web server. You can't do that as the communication will get really messed up as multiple server handlers try to respond to the same client.
As a test, you could force the client to connect only with webSocket (no polling at all to start) and see if the connection fails:
let socket = io(yourURL, {transports: ["websocket"]})'
socket.on('connect', () => {console.log("connected"});
socket.on('connect_error', (e) => {console.log("connect error: ", e});
socket.on('connect_timeout', (e) => {console.log("connect timeout: ", e});

Related

Relay a websocket from a third party to Node JS server to react front end

I'm trying to figure out how to relay this Polygon websocket from my Node JS server to my React front end. In other words, I want to establish a single websocket connection between Polygon and my server. I then want to relay that websocket so that any number of front end clients can establish a connection to that websocket from my server.
I'm able to connect my React front end to Polygon directly no problem, but only for internal testing since that doesn't scale (Polygon only accepts one websocket connection, don't want to expose Polygon API key to clients front end). Here is that code fwiw:
let socket;
useEffect(() => {
if (marketStatus() !== 'closed') {
socket = new WebSocket('wss://delayed.polygon.io/stocks');
socket.onopen = () => {
socket.send(
JSON.stringify({
action: 'auth',
params: 'API_KEY',
})
);
};
socket.onmessage = (event) => {
// console.log('Message from server ', event.data);
if (JSON.parse(event.data)[0].status === 'auth_success') {
console.log(JSON.parse(event.data)[0].status);
socket.send(JSON.stringify({ action: 'subscribe', params: `A.${props.ticker}` }));
}
if (JSON.parse(event.data)[0].ev === 'A') {
console.log(event.data)
}
};
return () => {
socket.close();
};
}
}, []);
I cannot find a simple example of the server code I need for the Node JS relay. Hoping there is one!

How to connect multiple socket clients nodejs

Scenario is i have a server where socket(1) runs i have one more server where socket(2) client connects to socket(1)
I have one browser socket which connects to socket(1)
Idea is to do request from browser and bring data from socket(2) server
Not sure how to difference between socket clients as all the sockets are similar to socket(1)
Ideally there will be multiple browser sockets and multiple socket(2) clients
Browser sockets can make request to any of the socket(2) clients
How to implement it using nodejs socket.io
Server
socket.on('action', (action) => {
if(action.type === 'server/hello'){
io.sockets.emit('broadcast',{ description: clients + ' clients connected!'});
console.log('Got hello data!', action.data);
}
});
Browser client
var socket = io.connect('localhost:3000', {reconnect: true});
socket.on('connect', function(data) {
socket.emit('joined', 'Hello World from client this is client plxx');
});
socket.on('response2', function(data) {
console.log("got it ", data);
$('#messages').append($('<li>').text(JSON.stringify(data)));
});
Server client
var io = require('socket.io-client');
var socket = io.connect('http://localhost:3000', {reconnect: true});
socket.on('broadcast', function (t) {
socket.emit("data", {data: 32})
console.log('broadcast! my host is est');
});
i should be able to communicate between socket clients
What I understood from your question is: you need to differentiate between sockets from different clients.
To solve that I would suggest simply emitting the socket source from the client on connect.
And on the server split the sockets into two lists.
Example:
Server
const BROWSER_CLIENTS = {};
const SERVER_CLIENTS = {};
io.on("connection", socket => {
socket.on("source", payload => {
if (payload == "browser")
BROWSER_CLIENTS[socket.id] = socket;
else if (payload == "server")
SERVER_CLIENTS[socket.id] = socket;
});
socket.on("disconnect", () => {
delete BROWSER_CLIENTS[socket.id];
delete SERVER_CLIENTS[socket.id];
});
});
Browser Client
socket.on("connect", () => {
socket.emit("source", "browser");
});
Server Client
socket.on("connect", () => {
socket.emit("source", "server");
});
Now when you receive an event you can detect from which source it originated. And if you need to send to all sockets of one type of clients you can simply do this:
Server
for (let i in BROWSER_CLIENTS)
BROWSER_CLIENTS[i].emit("Hello Browsers")
for (let i in SERVER_CLIENTS)
SERVER_CLIENTS[i].emit("Hello Servers")
EDIT: I found this link and thought you could make use of it. Socket.io Rooms

Socket.io keeps multiple connected sockets alive for 1 client

I am using Socket.io to connect a React client to a Node.js server and the query option in socket.io to identify uniquely every new client. However, the server creates multiple sockets for every client and, when I need to send something from the server, I don't know which socket use, because I have more than one, and all of them are connected.
The client code:
import io from "socket.io-client";
...
const socket = io(process.env.REACT_APP_API_URL + '?userID=' + userID, { forceNew: true });
socket.on('connect', () => {
socket.on('new-order', data => {
const { add_notification } = this.props;
add_notification(data);
});
The server code:
....
server = http
.createServer(app)
.listen(8080, () => console.log(env + ' Server listening on port 8080'));
io = socketIo(server);
io.on('connection', socket => {
const userID = socket.handshake.query.userID;
socket.on('disconnect', () => {
socket.removeAllListeners();
});
});
And here the server-side that emits events to the client:
for (const socketID in io.sockets.connected) {
const socket = io.sockets.connected[socketID];
if (socket.handshake.query.userID === userID) {
// Here, I find more than one socket for the same condition, always connected.
socket.emit(event, data)
}
}
Here, it is possible to see all these socket for the same client:
I tried to send events for all socket from a given userID, however, multiple events are triggered to the client, showing duplicated data to the user. I also tried to send events to the last socket, but, sometimes it works, sometimes doesn't.
Someone have a clue how to uniquely identify a socket when there are several clients?

How to test socket.io server when client emits

I want a client to emit a signal, and test the behaviour of my socket.io server when that signal is received. I have looked at this question and these blog posts:
jest
mocha, chai
but they seem to be directed at testing the client, rather than the server.
Here is an example of something that I am trying to implement:
test('should communicate with waiting for socket.io handshakes', (done) => {
socket_client.emit('example', 'some messages');
setTimeout(() => {
socket_server.on('example', message => {
expect(message).toBe('INCORRECT MESSAGE');
});
done();
}, 50);
When I run my test suit, this should fail, but doesn't.
Does anyone have a simple example of testing this sort of behaviour?
Currently I'm using jest but any framework is fine.
My set up and teardown of the socket.io server test is as below:
import * as http from 'http';
import ioBack from 'socket.io';
let socket_client;
let httpServer;
let httpServerAddr;
let socket_server;
beforeAll((done) => {
httpServer = http.createServer().listen();
httpServerAddr = httpServer.address();
socket_server = ioBack(httpServer);
done();
});
afterAll((done) => {
socket_server.close();
httpServer.close();
done();
});
I am using mocha for testing. But I am not sure what you are doing. In your backend socket server there is no listener that you defined.
Here is a small example for a test. Maybe that helps?!
Test case
var sockethost = websocketUrl;
socketclient = io.connect(sockethost);
socketclient.on('customerId', function(data) {
var data = {
customerId: 10,
}
socketclient.emit('customerId', data);
});
Server:
var io = require('socket.io')(http);
io.sockets.on('connection', function (socket) {
socket.emit('customerId', null);
});
So that is a very simple test. The backend server sends out the connected client 'customerId' the client has a listener for customerId and sends back its customerId. You can also do the other way around, that you have a listener in server, and an emit in client. But I am not completely sure what you are trying to do.

Test if socket is open and listening, node, socket.io

I want to know form a stand alone Node application if a remote server (running with Socket.io) is up and listening for incoming connections.
If the server is up and listening, then connect with socket-io.client, and if not, record something to a DB.
I don't know how to accomplish this with socket-io.client. The address has IP and Port, so I just can't ping to the IP without the port.
Any ideas? Thanks!
You can just attempt to make a socket.io connection to the server. If it succeeds, then it is listening. If it fails, then apparently it is not listening. Here's a way to do that:
// check a socket.io connection on another server from a node.js server
// can also by used from browser client by removing the require()
// pass hostname and port in URL form
// if no port, then default is 80 for http and 447 for https
// 2nd argument timeout is optional, defaults to 5 seconds
var io = require('socket.io-client');
function checkSocketIoConnect(url, timeout) {
return new Promise(function(resolve, reject) {
var errAlready = false;
timeout = timeout || 5000;
var socket = io(url, {reconnection: false, timeout: timeout});
// success
socket.on("connect", function() {
clearTimeout(timer);
resolve();
socket.close();
});
// set our own timeout in case the socket ends some other way than what we are listening for
var timer = setTimeout(function() {
timer = null;
error("local timeout");
}, timeout);
// common error handler
function error(data) {
if (timer) {
clearTimeout(timer);
timer = null;
}
if (!errAlready) {
errAlready = true;
reject(data);
socket.disconnect();
}
}
// errors
socket.on("connect_error", error);
socket.on("connect_timeout", error);
socket.on("error", error);
socket.on("disconnect", error);
});
}
checkSocketIoConnect("http://192.168.1.10:8080").then(function() {
// succeeded here
}, function(reason) {
// failed here
});

Resources