Why my socketio is not connecting with my socketio-client? - javascript

i am working on a chatapp project that needs a real time chatting so i have used socketio in my server side which is written in nodejs and than used socketio-client in my main chatapp react-native project.
But now a problem is coming my socket is not initializing. I'm not able to connect my server with my main app. I am using socketio and socketio client my both the socket version are same 4.5.1 but it's not even connecting. I have tried to use old version of socket but its also not working and I have also tried to change my localhost port to 4000 but it's also not working.
My server code:
const express = require('express');
var bodyParser = require('body-parser');
const app = express();
const http = require('http');
const server = http.createServer(app);
const { Server } = require("socket.io");
const io = new Server(server);
const port = process.env.PORT || 3000;
require('./src/config/database')
const user_routes = require('./src/user/users.routes');
app.use(bodyParser.urlencoded({extended: true}))
app.use(express.json())
app.get('/', (req, res) => {
res.sendFile(__dirname + '/index.html');
});
app.use('/User', user_routes)
io.on('connection', (socket) => {
console.log('a user connected');
socket.on('send_message',(data)=>{
console.log("received message in server side",data)
io.emit('received_message',data)
})
socket.on('disconnect', () => {
console.log('user disconnected');
});
});
server.listen(port, () => {
console.log( `Server running at http://localhost:${port}/`);
});
My app socketservice file code:
import io from 'socket.io-client';
const SOCKET_URL = 'http://localhost:3000'
class WSService {
initializeSocket = async () => {
try {
this.socket = io(SOCKET_URL, {
transports: ['websocket']
})
console.log("initializing socket", this.socket)
this.socket.on('connect', (data) => {
console.log("=== socket connected ====")
})
this.socket.on('disconnect', (data) => {
console.log("=== socket disconnected ====")
})
this.socket.on('error', (data) => {
console.log("socekt error", data)
})
} catch (error) {
console.log("scoket is not inialized", error)
}
}
emit(event, data = {}) {
this.socket.emit(event, data)
}
on(event, cb) {
this.socket.on(event, cb)
}
removeListener(listenerName) {
this.socket.removeListener(listenerName)
}
}
const socketServcies = new WSService()
export default socketServcies
Where I have marked it should be connected = true but it's false in the dev console I have done console log so check that it's connecting or not and I can see that it's not connecting. How to make it connect?
There is no error in my app or server I have checked many times and my server is also running when I am running my app.

Answering my own question
The problem was i was using android emulator and android in an emulator can't connect to localhost you need to use the proxy ip so when i add http://10.0.2.2:3000 in const SOCKET_URL = 'http://10.0.2.2:3000' than its working fine
credit goes to gorbypark who told me this in discord

I'm assuming that your front and back runs in localhost. The documentation says that if the front-end is in the same domain as the back-end, you don't need to use the URL. Since you have the options parameter declared, you can use the default argument window.location in first place:
class WSService {
initializeSocket = async () => {
try {
this.socket = io(window.location, {
transports: ['websocket']
})
console.log("initializing socket", this.socket)
this.socket.on('connect', (data) => {
console.log("=== socket connected ====")
})
this.socket.on('disconnect', (data) => {
console.log("=== socket disconnected ====")
})
this.socket.on('error', (data) => {
console.log("socekt error", data)
})
} catch (error) {
console.log("scoket is not inialized", error)
}
}
emit(event, data = {}) {
this.socket.emit(event, data)
}
on(event, cb) {
this.socket.on(event, cb)
}
removeListener(listenerName) {
this.socket.removeListener(listenerName)
}
}

Don't specify the host/port for socket-io to connect to. It can figure it out on its own.
Per documentation, it tries to connect to window.location if no URL is specified as an argument.
So instead of
this.socket = io(SOCKET_URL, {
transports: ['websocket']
})
Just do
this.socket = io()
I am not sure it works with other arguments. You could try like this
this.socket = io(undefined, {
transports: ['websocket']
})

Related

mongoose fails to connect on first attempt

I'm using nodejs, express, and mongoose (6.9.0) on my app. It's deployed on Vercel, the first time I try to call to the api from my frontend app, the api shows me the following error on console
MongoDB disconnectedMongoose default connection has occured: MongooseServerSelectionError: Could not connect to any servers in your MongoDB Atlas cluster. One common reason is that you're trying to access the database from an IP that isn't whitelisted. Make sure your current IP address is on your Atlas cluster's IP whitelist: https://docs.atlas.mongodb.com/security-whitelist/
My api is wishlisted on MongoDB, and this only happens on the first call to the api, the next calls works perfectly. (this only happens in production)
This is my connect function
const { MONGO_DB_URI_TEST } = process.env;
const connectionString = MONGO_DB_URI_TEST;
const mongooseOptions = {
useUnifiedTopology: true,
useNewUrlParser: true,
};
if (!connectionString) {
console.error("Failed to import .env");
}
const connectMongo = () => {
mongoose.connect(connectionString, mongooseOptions);
mongoose.connection.on("connected", () => {
console.log("MongoDB is connected");
});
mongoose.connection.on("error", (error) => {
console.log(`Mongoose default connection has occured: ${error}`);
process.exit();
});
mongoose.connection.on("disconnected", () => {
console.log("MongoDB disconnected");
});
process.on("uncaughtException", () => {
mongoose.disconnect();
});
const closeConnection = function () {
mongoose.connection.close(() => {
console.log("MongoDB disconnected due to app termination");
process.exit(0);
});
};
process.on("SIGINT", closeConnection).on("SIGTERM", closeConnection);
};
export { connectMongo };
app.js (it has many middlewares irrelevant here)
const app = express();
connectMongo();
app.use("/", router);
export { app };
index.js
import { app } from "./src/app.js";
const PORT = process.env.PORT || 4000;
const server = app.listen(PORT, () => {
console.log("Server listening on port", PORT);
});
export default server;
How can I solve this? Thanks in advance.

how to Get all connected clients in socket.io

I have socket.io v2.3 and I'm trying to get all connected sockets from a different file. Here's my setup:
const io = require('socket.io');
let IO;
let myNameIO;
module.exports = {
create: (server) => {
IO = io(server, { cors: { origin: '*' } });
const redisConnection = redisAdapter({ host: redisHost, port: redisPort });
IO.adapter(redisConnection);
IO.on('connection', (socket) => {
console.log('a user connected');
});
IO.on('disconnect', (socket) => {
console.log('disconnected');
});
myNameIO = IO.of('/my-name');
myNameIO.on('connection', function (socket) {
console.log('someone connected');
});
},
getIO: () => IO,
getMyNameIO: () => myNameIO,
};
IN a diff file I import getMyNameIO and I'm trying to get all connected clients but I'm having trouble with that. Tried doing
getMyNameIO().clients((error, clients) => {
console.log(clients, '-=--=-=');
});
But clients isn't a function. I then tried importing the socket.io and use.of, but that doesn't return anything. What am doing wrong and how can I fix it?
Give this a try. I suspect either a scope issue or order of operations issue. Either way this should resolve it or give you a more useful error. I've tried to maintain your naming scheme which gave me a small headache. =)
const io = require('socket.io');
const socketServer = {
_initialized: false,
_myNameIO: null,
_IO: null,
_myNameIOClients: new Map(),
get myNameIO() {
if (!socketServer._initialized) throw new Error('socketServer.create not called!')
return socketServer._myNameIO
},
get IO() {
if (!socketServer._initialized) throw new Error('socketServer.create not called!')
return socketServer._IO
},
create: (server) => {
IO = io(server, { cors: { origin: '*' } });
const redisConnection = redisAdapter({ host: redisHost, port: redisPort });
IO.adapter(redisConnection);
IO.on('connection', (socket) => {
console.log('a user connected');
});
IO.on('disconnect', (socket) => {
console.log('disconnected');
});
myNameIO = IO.of('/my-name');
myNameIO.on('connection', function (socket) {
console.log('someone connected');
socketServer._myNameIOClients.set(socket.id, socket)
});
},
//getIO: () => IO,
//getMyNameIO: () => myNameIO,
getIO: () => socketServer._IO,
getMyNameIO: () => socketServer._myNameIO,
get myNameIOClients() {
return socketServer._myNameIOClients
},
getClients: () => new Promise((resolve,reject)=>socketServer._myNameIO.clients((error, clients)=> error ? reject(error) : resolve(clients))
}),
};
module.exports = socketServer
when I do console.log(socketServer.myNameIO.sockets); I get an object with all the sockets. how can I get an array?
Looking at the API https://socket.io/docs/v2/server-api/#Namespace I don't see a reference to Namespace.sockets. That doesn't mean it doesn't exist. I added a getClients function that will return an array of client IDs.
const socketServer = require('./socketServer ')
socketServer.getClients()
.then(clients=>{
// clients an array of client IDs
})
.catch(e=>console.error('Error is socketServer.getClients()', e))
I think what you really want is to manage the connections. One way to do it is by mapping the connections as they come in.
const socketServer = require('./socketServer ')
// This is a Map
let myNameIOClients = socketServer.myNameIOClients
// We can easily turn it into an array if needed
let myNameIOClientsArray = Array.from(socketServer.myNameIOClients)

How To Implement React hook Socketio in Next.js

I have tried to find a way from Google but the results can remain the same
 http://localhost:8000/socket.io/?EIO=3&transport=polling&t=MnHYrvR
i try this wan medium try other ways, the results remain the same
and for the front end I have tried, socket io inside the hook component and outside the scope, the results remain the same
http://localhost:8000/socket.io/?EIO=3&transport=polling&t=MnHYrvR
this is my code from server:
app.prepare().then(() => {
const server = express();
const setServer = require('http').Server(server);
const io = require('socket.io')(setServer)
server.use(bodyParser.json());
server.use(cookieParser());
io.on('connection', socket => {
console.log('socket', socket);
socket.emit('now', {
message: 'zeit'
})
})
server.use(routers)
server.get('*', (req, res) => {
return handle(req, res);
});
server.use( (err, req, res, next) => {
console.log(err)
if(err.name === 'Error'){
res.status(401).send({
title: 'error',
detail: 'Unauthorized Access!'
})
}
})
server.listen(port, err => {
if (err) throw err;
console.log(`> Ready on http://heroku:${port}`)
})
})
.catch(ex => {
console.error(ex.stack);
process.exit(1);
});
from front end:
//at the top of function
const io = require('socket.io-client');
const socket = io.connect('http://localhost:8000');
console.log('socket', socket);
//in use effect
useEffect(() =>{
socket.on('now', message => {
console.log('message', meesage);
})
})
Please help
Although I am not using Next.js, I have a similar setup with Express.js that might help you with your problem...
On my Node.js side I have the following setup:
const app = require('express')()
const server = require('http').createServer(app)
const io = require('socket.io')(server)
// ...
io.sockets.on('connection', () => {
console.log(`Client with ID of ${socket.id} connected!`)
io.sockets.emit('SOME_EVENT', 'HelloWorld')
})
Then, my frontend with React looks like this:
import React from 'react'
import io from 'socket.io-client'
function useSocket(url) {
const [socket, setSocket] = useState(null)
useEffect(() => {
const socketIo = io(url)
setSocket(socketIo)
function cleanup() {
socketIo.disconnect()
}
return cleanup
// should only run once and not on every re-render,
// so pass an empty array
}, [])
return socket
}
function App() {
const socket = useSocket('http://127.0.0.1:9080')
useEffect(() => {
function handleEvent(payload) {
console.log(payload)
// HelloWorld
}
if (socket) {
socket.on('SOME_EVENT', handleEvent)
}
}, [socket])
return (...)
}
Also, one common error that I am seeing when working with socket.io is the following:
Cross-Origin Request Blocked: The Same Origin Policy disallows
reading the remote resource at
http://127.0.0.1:9080/socket.io/?EIO=3&transport=polling&t=MnH-W4S.
(Reason: CORS request did not succeed).
This is due an incorrect URL that's provided as a parameter in the socket manager creation process:
const socket = io('http://localhost');
So just double check that the address you're providing is correct. If you're serving your application on now and accessing it through a now.sh URL, but providing http://localhost as your URL parameter, then it won't work.
(I realise that this is an old/stale question, but in the spirit of "The Wisdom of the Ancients".)
I came across this question because I had the exact same problem. I realised that I was using the wrong server to listen with. Instead of Express, you should use the HTTP module.
const setServer = require('http').Server(server);
const io = require('socket.io')(setServer)
So, this part...
server.listen(port, err => {
if (err) throw err;
console.log(`> Ready on http://heroku:${port}`)
})
...should become:
setServer.listen(port, err => {
if (err) throw err;
console.log(`> Ready on http://heroku:${port}`)
})

NextJS, Express, Error during WebSocket handshake: Unexpected response code: 200

The basic problem can be summarized as follows: When creating a Websocket server in Node using ws with the server option populated by an express server(as in this example), while using that same express server to handle the routing for NextJS (as in this example), the upgrade header seems to not be properly parsed.
Instead of the request being routed to the Websocket server, express sends back an HTTP 200 OK response.
I've searched high and low for an answer to this, it may be that I simply do not understand the problem. A possibly related question was brought up in an issue on NextJS's github. They recommend setting WebsocketPort and WebsocketProxyPort options in the local next.config.js, however I have tried this to no avail.
A minimal example of the relevant server code can be found below. You may find the full example here.
const express = require('express')
const next = require('next')
const SocketServer = require('ws').Server;
const port = parseInt(process.env.PORT, 10) || 3000
const dev = process.env.NODE_ENV !== 'production'
const app = next({ dev })
const handle = app.getRequestHandler()
app.prepare().then(() => {
const server = express()
server.all('*', (req, res) => {
return handle(req, res)
})
server.listen(port, err => {
if (err) throw err
console.log(`> Ready on http://localhost:${port}`)
})
const wss = new SocketServer({ server });
wss.on('connection', function connection(ws, request) {
console.log('Client connected');
ws.on('close', () => console.log('Client disconnected'));
});
wss.on('error', function (error) {
console.log(error);
});
setInterval(() => {
wss.clients.forEach((client) => {
client.send(new Date().toTimeString());
});
}, 1000);
}).catch(ex => {
console.error(ex.stack);
process.exit(1);
});
The expected result, of course, is a connection to the websocket server. Instead I receive the following error:
WebSocket connection to 'ws://localhost:3000/' failed: Error during WebSocket handshake: Unexpected response code: 200
Can anyone elucidate anything for me here?
Ok, after more digging I have solved the problem. Quite simply, the ws.Server object to which I was trying to feed the server = express() object is not strictly speaking an http server object. However, server.listen() returns such an http server object. On such an object we can listen for an 'upgrade' call, which we can pass to our ws.Server object's handleUpgrade() event listener, through which we can connect. I will be updating the examples that I linked in my question, but the relevant code is below:
app.prepare().then(() => {
const server = express()
server.all('*', (req, res) => {
return handle(req, res)
})
const wss = new SocketServer({ server });
wss.on('connection', function connection(ws, request) {
console.log('Client connected');
ws.on('close', () => console.log('Client disconnected'));
});
wss.on('error', function (error) {
console.log(error);
});
let srv = server.listen(port, err => {
if (err) throw err
console.log(`> Ready on http://localhost:${port}`)
})
srv.on('upgrade', function(req, socket, head) {
wss.handleUpgrade(req, socket, head, function connected(ws) {
wss.emit('connection', ws, req);
})
});

How to send broadcast to all connected client in node js

I'm a newbie working with an application with MEAN stack. It is an IoT based application and using nodejs as a backend.
I have a scenario in which I have to send a broadcast to each connected clients which can only open the Socket and can wait for any incoming data. unless like a web-browser they can not perform any event and till now I have already gone through the Socket.IO and Express.IO but couldn't find anything which can be helpful to achieve what I want send raw data to open socket connections'
Is there any other Node module to achieve this. ?
Here is the code using WebSocketServer,
const express = require('express');
const http = require('http');
const url = require('url');
const WebSocket = require('ws');
const app = express();
app.use(function (req, res) {
res.send({ msg: "hello" });
});
const server = http.createServer(app);
const wss = new WebSocket.Server({ server });
wss.on('connection', function connection(ws) {
ws.on('message', function(message) {
wss.broadcast(message);
}
}
wss.broadcast = function broadcast(msg) {
console.log(msg);
wss.clients.forEach(function each(client) {
client.send(msg);
});
};
server.listen(8080, function listening() {
console.log('Listening on %d', server.address().port);
});
Now, my query is when this code will be executed,
wss.on('connection', function connection(ws) {
ws.on('message', function(message) {
wss.broadcast(message);
}
}
var WebSocketServer = require("ws").Server;
var wss = new WebSocketServer({port:8100});
wss.on('connection', function connection(ws) {
ws.on('message', function(message) {
wss.broadcast(message);
}
}
wss.broadcast = function broadcast(msg) {
console.log(msg);
wss.clients.forEach(function each(client) {
client.send(msg);
});
};
Try the following code to broadcast message from server to every client.
wss.clients.forEach(function(client) {
client.send(data.toString());
});
Demo server code,
const WebSocket = require('ws')
const wss = new WebSocket.Server({ port: 2055 },()=>{
console.log('server started')
})
wss.on('connection', (ws) => {
ws.on('message', (data) => {
console.log('data received \n '+ data)
wss.clients.forEach(function(client) {
client.send(data.toString());
});
})
})
wss.on('listening',()=>{
console.log('listening on 2055')
})

Categories