multiple sessions established to socket io - javascript

I'm new to node and trying to create a server with socketio to send messages to front (react). But when I run the server and many connections begin to be established it shows something like this :
Listening on port 3000
client connectedLv3LqI9EhmYTLBIIAAAA
client connectedrKLlxRPDkRs20L43AAAB
client connectedHAUuOADubCigGNTzAAAC
client connectedFF1dTRFe-HFublfgAAAD
Here is my code :
var express = require("express");
var app = express();
const http = require("http");
const SocketIO = require("socket.io");
//database connections
let user;
const MongoClient = require("mongodb").MongoClient;
const uri = "mongodb://localhost:27017/?replicaSet = rs01";
const client = new MongoClient(uri, {
useNewUrlParser: true,
useUnifiedTopology: true,
});
client.connect().then((db) => {
let requests = 0;
let responses = 0;
let transactions = 0;
const changeStream = client
.db("gardesh_pay_silk")
.collection("silk_profile")
.watch();
changeStream.on("change", (next) => {
console.log(next);
});
const silkProfileQueries = client
.db("gardesh_pay_silk")
.collection("silk_profile_queries")
.watch();
silkProfileQueries.on("change", (next) => {
console.log(next);
});
const silkSQLQueries = client
.db("gardesh_pay_silk")
.collection("silk_sqlquery")
.watch();
silkSQLQueries.on("change", (next) => {
console.log(next);
transactions += 1;
});
const silkRequest = client
.db("gardesh_pay_silk")
.collection("silk_request")
.watch();
silkRequest.on("change", (next) => {
console.log(next);
user.broadcast.emit("requested", next);
requests++;
});
const silkResponse = client
.db("gardesh_pay_silk")
.collection("silk_response")
.watch();
silkResponse.on("change", (next) => {
console.log(next);
responses += 1;
});
console.log(requests);
});
const server = http.createServer(app);
const io = SocketIO(server);
io.on("connection", (client) => {
user = client;
console.log("client connected"+client.id);
client.on("disconnect", () => {
console.log("user disconnected");
});
});
const port = process.env.PORT || 3000;
server.listen(port, () => console.log('Listening on port'+port));
I think that the problem is in this part of code:
const server = http.createServer(app);
const io = SocketIO(server);
io.on("connection", (client) => {
user = client;
console.log("client connected"+client.id);
client.on("disconnect", () => {
console.log("user disconnected");
});
});
and here is my connection in client side :
import { socketIOClient, io } from "socket.io-client";
import { type } from "jquery";
class Again extends React.Component {
timing=()=> {
this.props.req_changer(this.requests);
this.props.res_changer(this.responses);
this.props.trans_changer(this.transactions);
this.requests = 0;
this.responses = 0;
this.transactions = 0;
}
constructor(props) {
super(props);
this.state = {
endpoint: "http://127.0.0.1:4000",
requested: "undefined",
};
}
componentDidMount() {
this.count = setInterval(this.timing, 1000);
}
componentWillUnmount() {
clearInterval(this.count);
}
render() {
const socket = socketIOClient(this.state.endpoint);
socket.on("requested", (object) => {
if (object.ns.coll == "silk_request") {
this.requests++;
}
if (object.ns.coll == "silk_response") {
this.responses++;
}
if (object.ns.coll == "silk_sqlquery") {
this.transactions++;
}
});
return <div></div>;
}
}
export default Again;```

There is some issues in your code.
A) Client side:
Don't put the const socket & socket.on into the render method. The render method should contain only the visualizations (UI if you want)...
The creation of the socket constant -can be- in the class's constructor, or, outside of the class:
const socket = socketIOClient(this.state.endpoint);
class Again extends React.Component {
.
.
.
}
The listening of the sockets requests should be under the componentDidMount() function:
componentDidMount() {
socket.on("requested", (object) => {
if (object.ns.coll == "silk_request") {
this.requests++;
}
if (object.ns.coll == "silk_response") {
this.responses++;
}
if (object.ns.coll == "silk_sqlquery") {
this.transactions++;
}
});
}
B) Server side:
this is the important issue, the 'Client' attribute you used is a socket:
io.on("connection", (socket) => {
.
.
});
Every socket has a session. So for the same client we can have multiple sessions at the same time (for example, for every refreshing of the application). So you need to save the client's sessions. To do it, you can use the express session middleware:
io.use((socket, next) => {
app.sessionMiddleware(socket.request, {}, next);
});
io.on("connection", (socket) => {
const session = socket.request.session;
session.save();
});
You need also to save all sessions (if the client use multiple navigators for exemple, the server should send the requests for all of them, bu sockets), and then to delete them when client disconnecting:
var onlineClients = {};
var socketToClient = {};
io.on('connection', (socket) => {
const session = socket.request.session;
session.save();
if(onlineClients[session.clientID] === undefined){
onlineClients[session.clientID] = {
sockets: []
}
}
socketToClient[socket.id] = session.clientID;
onlineClients[session.clientID].sockets.push(socket);
.
.
.
socket.on('disconnect', () => {
let clientId = socketToClient[socket.id]
if(clientId){
let clientSockets = onlineClients[clientId].sockets
clientSockets = clientSockets.filter(s => socket.id !== s.id)
onlineClients[clientId].sockets = clientSockets
if(clientSockets.length === 0){
delete onlineClients[clientId]
}
}
});
Conclusion: your question title should be: multiple sessions established to socket io
Hope it can help you!

here is my node server code :
var app = express();
const http = require("http");
const SocketIO = require("socket.io");
// database connections
let user;
const MongoClient = require("mongodb").MongoClient;
const uri = "mongodb://localhost:27017/?replicaSet = rs01";
const client = new MongoClient(uri, {
useNewUrlParser: true,
useUnifiedTopology: true,
});
client.connect().then((db) => {
let requests = 0;
let responses = 0;
let transactions = 0;
const changeStream = client
.db("gardesh_pay_silk")
.collection("silk_profile")
.watch();
changeStream.on("change", (next) => {
console.log(next);
});
const silkProfileQueries = client
.db("gardesh_pay_silk")
.collection("silk_profile_queries")
.watch();
silkProfileQueries.on("change", (next) => {
console.log(next);
});
const silkSQLQueries = client
.db("gardesh_pay_silk")
.collection("silk_sqlquery")
.watch();
silkSQLQueries.on("change", (next) => {
console.log(next);
transactions += 1;
});
const silkRequest = client
.db("gardesh_pay_silk")
.collection("silk_request")
.watch();
silkRequest.on("change", (next) => {
console.log(next);
user.broadcast.emit("requested", next);
requests++;
});
const silkResponse = client
.db("gardesh_pay_silk")
.collection("silk_response")
.watch();
silkResponse.on("change", (next) => {
console.log(next);
responses += 1;
});
console.log(requests);
});
const server = http.createServer(app);
var onlineClients = {};
var socketToClient = {};
const io = SocketIO.listen(4000);
io.use((socket, next) => {
app.sessionMiddleware(socket.request, {}, next);
});
io.on('connection', (socket) => {
const session = socket.request.session;
this.user = socket;
session.save();
if (onlineClients[session.clientID] === undefined) {
onlineClients[session.clientID] = {
sockets: []
}
}
socketToClient[socket.id] = session.clientID;
onlineClients[session.clientID].sockets.push(socket);
socket.on('disconnect', () => {
let clientId = socketToClient[socket.id]
if (clientId) {
let clientSockets = onlineClients[clientId].sockets
clientSockets = clientSockets.filter(s => socket.id !== s.id)
onlineClients[clientId].sockets = clientSockets
if (clientSockets.length === 0) {
delete onlineClients[clientId]
}
}
});
});
const port = process.env.PORT || 3000;
server.listen(port, () => console.log(`Listening on port ${port}`));
it is just a very simple server that watch's for changes in mongodb...

Related

Websocket detect client disconnect fails

I am using the following logic to verify whether client is connected to websocket or not: Client keeps sending pings at an interval to the server. Server has a timeout which triggers an event on completing. As soon as Client pings server, the server timeout resets. This works fine when one client is connected. But the logic breaks on multiple clients. How can I fix this? As soon as 2nd client connects, Server says client 1 has disconnected and doesn't print anything when either of the 2 disconnect.
This is my server logic:
const WebSocket = require("ws");
const express = require("express");
const app = express();
const server = require("http").createServer(app);
const url = require('url');
const PORT = process.env.PORT || 3000;
const wss = new WebSocket.Server({ server: server });
app.get("/", (req, res) => res.send("Temst."));
var tm;
function ping(client) {
tm = setTimeout(function () {
console.log(`[-] ${client} Disconnected`);
wss.emit("customClose", client);
}, 5000);
}
function pong(client) {
clearInterval(tm);
// console.log("[!] Cleared timeout");
ping(client);
}
wss.on("connection", function connection(ws, req) {
var queryData = url.parse(req.url,true).query;
ping(queryData.id);
console.log(`[+] ${req.socket.remoteAddress} Connected`);
wss.clients.forEach(function each(client) {
if (client.readyState === WebSocket.OPEN) {
message = {
type: "alert",
msg: `${queryData.id} has Connected.`,
};
client.send(JSON.stringify(message), { binary: false });
}
});
ws.on("message", function incoming(message) {
if (message == "__ping__") {
console.log(`[!] Ping Receieved from ${req.socket.remoteAddress}`);
pong(queryData.id);
} else {
`[!] Message Receieved from ${req.socket.remoteAddress}`;
wss.clients.forEach(function each(client) {
if (client.readyState === WebSocket.OPEN) {
client.send(msg, { binary: false });
}
});
}
});
});
wss.addListener("customClose", function (m) {
wss.clients.forEach(function each(client) {
if (client.readyState === WebSocket.OPEN) {
message = {
type: "alert",
msg: `${m} has Disconnected.`,
};
client.send(JSON.stringify(message), { binary: false });
}
});
});
server.listen(PORT, () => console.log("Listening on port 3000"));
I think I have solved the problem. After looking at the ws package docs, I tried server side pinging instead of client side. It is working for multiple users for now. Will update if any problems occur.
const WebSocket = require("ws");
const express = require("express");
const app = express();
const server = require("http").createServer(app);
const url = require("url");
const PORT = process.env.PORT || 3000;
const wss = new WebSocket.Server({ server: server });
app.get("/", (req, res) => res.send("Temst."));
var myClients = [];
wss.on("connection", function connection(ws, req) {
var queryData = url.parse(req.url, true).query;
myClients.push({
id: queryData.id,
wsoc: ws,
isAlive: true,
});
console.log(`[+] ${req.socket.remoteAddress} Connected`);
wss.clients.forEach(function each(client) {
if (client.readyState === WebSocket.OPEN) {
message = {
type: "alert",
msg: `${queryData.id} has Connected.`,
};
client.send(JSON.stringify(message), { binary: false });
}
});
ws.on("pong", () => {
let x = myClients.find((o) => o.wsoc === ws);
x.isAlive = true;
});
ws.on("message", function incoming(message) {
console.log(`[!] Message Receieved from ${req.socket.remoteAddress}`);
msg = JSON.parse(message);
console.log(queryData);
msg = { ...msg, time: new Date().toISOString() };
wss.clients.forEach(function each(client) {
if (client.readyState === WebSocket.OPEN) {
client.send(JSON.stringify(msg), { binary: false });
}
});
});
});
wss.addListener("customClose", function (m) {
wss.clients.forEach(function each(client) {
if (client.readyState === WebSocket.OPEN) {
message = {
type: "alert",
msg: `${m} has Disconnected.`,
};
client.send(JSON.stringify(message), { binary: false });
}
});
});
const interval = setInterval(function ping() {
myClients.forEach((clnt, index) => {
if (clnt.isAlive === false) {
console.log("[-]", clnt.id, "has Disconnected.");
wss.emit("customClose", clnt.id);
clnt.wsoc.terminate();
myClients.splice(index, 1);
}
clnt.isAlive = false;
clnt.wsoc.ping();
});
}, 5000);
server.listen(PORT, () => console.log("Listening on port 3000"));

How to debug Node + Socket.io CPU Issues, doing nothing but connections 100% cpu

I'm running a Node Socket.io server with Express with docker compose
and client side is vue.js. The service is running well, but the CPU grows 100
and stays, i'm every time doing restart to my docker compose,still after 5 minutes cpu reaches jumping 100%.. I don't know what to check since there's laterally nothing but the most basic stuff..client and server connection and disconnect works perfect,all events is working good but i don't know which way i ll focus to find my bugs.
Here are my backend code socket code.
import { verifyToken } from './middleware/auth';
import Socket from './components/services/socket';
const app = express();
const socketPort = process.env.SOCKET_PORT || 8001;
const io = require('socket.io')(socketPort);
const port = process.env.PORT || 3000;
app.listen(port, () => {
log.info(`HTTP server is running 🚀 on port ${port}
Socket service running 🚀 on port ${socketPort}
Process Pid: ${process.pid}`);
});
const socket = new Socket(io);
socket.modelLoaded();
socket.js file______________
import { socketTokenVerification } from './../../middleware/auth';
export default class {
constructor(io) {
this.io = io;
this.connections = {};
}
addConnection(socket) {
if (this.connections[socket.user_id]) {
this.socketDisconnect(this.connections[socket.user_id]);
}
this.connections[socket.user_id] = {
id: socket.id,
isAuthenticated: true,
user_id: socket.user_id
};
}
removeConnection(socket) {
delete this.connections[socket.user_id];
}
socketDisconnect(socket) {
if (this.io.sockets.connected[socket.id]) {
this.io.sockets.connected[socket.id].disconnect(true);
}
}
modelLoaded() {
const { io, connections } = this;
io.on('connection', socket => {
const authData = socketTokenVerification(socket);
if (authData.error) {
io.to(socket.id).emit('error', {
message: authData.message
});
this.socketDisconnect(socket);
return;
}
const { user_id } = authData;
socket.user_id = user_id;
this.addConnection(socket);
User.connected(socket.user_id);
socket.on('disconnect', () => {
this.removeConnection(socket);
User.disconnect(user_id);
this.socketDisconnect(socket);
Object.keys(io.sockets.connected).length);
});
Client side code.
import io from 'socket.io-client';
socket = io(ENDPOINT, {
transports: ['websocket'],
});
socket.on('connect', () => {
console.log('conected');
});
socket.on('disconnect', () => {
console.log('disconnected');
});
socket.on('reconnect', () => {
console.log('reconnect');
});
socket.on('receive_message', (receiveMsg) => {
console.log(recMsg, 'mes');
});
socket.on('error', (err) => {
console.log(err, 'err');
});
},
beforeDestroy() {
socket.disconnect(true);
},

no response socket.io with reactjs

two info: [HMR] Waiting for update signal from WDS...
Download the React DevTools for a better development experience: fb.me/react-devtools
error: http://127.0.0.1:4001/socket.io/?EIO=3&transport=polling&t=N4qdmGu
Failed to load resource: net::ERR_CONNECTION_REFUSED what should be done to make this work?
const express = require("express");
const http = require("http");
const socketIo = require("socket.io");
const axios = require("axios");
const port = process.env.PORT || 4001;
const index = require("./routes/index");
const app = express();
app.use(index);
const server = http.createServer(app);
const io = socketIo(server);
let interval;
io.on("connection", socket => {
console.log("New client connected");
if (interval) {
clearInterval(interval);
}
interval = setInterval(() => getApiAndEmit(socket), 10000);
socket.on("disconnect", () => {
console.log("Client disconnected");
});
});
const getApiAndEmit = async socket => {
try {
const res = await axios.get(
"https://api.darksky.net/forecast/db057094f57ede5e1f8d33d5e528e4b3/30.9871097,34.9408864"
);
let temp = (((res.data.currently.temperature - 32) * 5) / 9).toFixed(2);
socket.emit("FromAPI", temp);
} catch (error) {
console.error(`Error: ${error.code}`);
}
};
server.listen(port, () => console.log(`Wee wee i'm on port ${port}`));
than
import React, { Component } from "react";
import socketIOClient from "socket.io-client";
class App extends Component {
constructor() {
super();
this.state = {
response: false,
endpoint: "http://127.0.0.1:4001"
};
}
componentDidMount() {
const socket = socketIOClient(this.state.endpoint);
socket.on("FromAPI", data => this.setState({ response: data }));
}
render() {
const { response } = this.state;
return (
<div style={{ textAlign: "center" }}>
{
response ?
(<p>The temperature is {response} degrees</p>)
:
(<p>load load...</p>)
}
</div>
);
}
}
export default App;
You have to first connect to the socket server on the client side so for that add this
socket.on('connect', function(){});
before your event listener.
socket.on("FromAPI", data => this.setState({ response: data }));

Why no response socket.io with react.js

server side:
const express = require("express");
const http = require("http");
const socketIo = require("socket.io");
const axios = require("axios");
const port = process.env.PORT || 4001;
const index = require("./routes/index");
const app = express();
app.use(index);
const server = http.createServer(app);
const io = socketIo(server);
let interval;
io.on("connection", socket => {
console.log("New client connected");
if (interval) {
clearInterval(interval);
}
interval = setInterval(() => getApiAndEmit(socket), 10000);
socket.on("disconnect", () => {
console.log("Client disconnected");
});
});
const getApiAndEmit = async socket => {
try {
const res = await axios.get(
"https://api.darksky.net/forecast/db057094f57ede5e1f8d33d5e528e4b3/30.9871097,34.9408864"
);
let temp = (((res.data.currently.temperature - 32) * 5) / 9).toFixed(2);
socket.emit("FromAPI", temp);
} catch (error) {
console.error(`Error: ${error.code}`);
}
};
server.listen(port, () => console.log(`Wee wee i'm on port ${port}`));
client side:
import React, { Component } from "react";
import socketIOClient from "socket.io-client";
class App extends Component {
constructor() {
super();
this.state = {
response: false,
endpoint: "http://127.0.0.1:4001"
};
}
componentDidMount() {
const socket = socketIOClient(this.state.endpoint);
socket.on("FromAPI", data => this.setState({ response: data }));
}
render() {
const { response } = this.state;
return (
<div style={{ textAlign: "center" }}>
{
response ?
(<p>The temperature is {response} degrees</p>)
:
(<p>load load...</p>)
}
</div>
);
}
}
export default App;
2 info:
[HMR] Waiting for update signal from WDS...
Download the React DevTools for a better development experience: fb.me/react-devtools
1 error:
http://127.0.0.1:4001/socket.io/?EIO=3&transport=polling&t=N4qdmGu
Failed to load resource: net::ERR_CONNECTION_REFUSED
What's wrong?
You should try to set endpoint in client side to 'http://localhost:4001'.

Issues connecting to Node JS websocket using 'connection' keyword

I am setting up a peer to peer server for a blockchain project which leverages the Node JS ws websocket client. For whatever reason, the arrow function in my server.on(...) call does not execute. When I change the keyword to 'listen' however, the function executes. Please help :P.
p2p-server.js:
const Websocket = require('ws');
const P2P_PORT = process.env.P2P_PORT || 5001;
const peers = process.env.peers ? process.env.PEERS.split(',') : [];
// HTTP_PORT=3002 P2P_PORT=5003 PEERS=ws://localhost:5001,ws://localhost:5002 npm run dev
// HTTP_PORT=3002 P2P_PORT=5002 PEERS=ws://localhost:5001 npm run dev
class P2pServer {
constructor (Blockchain) {
this.blockchain = Blockchain;
this.sockets = [];
}
listen() {
const server = new Websocket.Server({ port: P2P_PORT });
// server.on('connection', socket => this.connectSocket(socket));
server.on('connection', socket => this.connectSocket(socket));
// this.connectToPeers();
console.log(`Listening for peer-to-peer connections on: ${P2P_PORT}`);
}
// connectToPeers() {
// peers.forEach(peer => {
// const socket = new Websocket(peer);
// socket.on('open', () => this.connectSocket(socket));
// });
// }
connectSocket(socket) {
this.sockets.push(socket);
console.log('Socket connected.')
}
}
module.exports = P2pServer;
index.js:
// REST API
const express = require('express');
const bodyParser = require('body-parser');
const BlockChain = require('../blockchain');
const P2pServer = require('./p2p-server');
const HTTP_PORT = process.env.HTTP_PORT || 3001;
const app = express();
const bc = new BlockChain();
const p2pServer = new P2pServer(bc)
app.use(bodyParser.json());
app.get('/blocks', (req, res) => {
res.json(bc.chain);
});
app.post('/mine', (req, res) => {
const block = bc.addBlock(req.body.data);
console.log(`New block added: ${block.toString()}`);
res.redirect('/blocks');
})
app.listen(HTTP_PORT, () => console.log(`Listening on port ${HTTP_PORT}`));
p2pServer.listen();
simple syntax error messed me up in line 3.
This...
const peers = process.env.peers ? process.env.PEERS.split(',') : [];
should have been this...
const peers = process.env.PEERS ? process.env.PEERS.split(',') : [];

Categories

Resources