Address already in use with Socket.io in Express - javascript

I'm trying to use websockets in my app but I'm not able to get Socket.io to connect to my server. Whenever I run the code below, I get this error:
Error: listen EADDRINUSE: address already in use :::3000
I've tried looking up some solutions, and I found that there's no other processes running on this port, so the issue has to be within the project. What could I be doing wrong here?
const express = require("express");
const mongoose = require("mongoose");
const app = express();
const { createServer } = require("http");
const httpServer = createServer(app);
const socketIO = require("socket.io")(3000, { cors: { origin: "*" } });
socketIO.on("connection", (socket) => {
console.log("connected");
});
const port = 3000;
const startServer = () => {
httpServer.listen(port);
console.log(`Listening on port ${port} 🚀`);
};
mongoose
.connect(uri)
.then(() => startServer())
.catch((err) => {
console.log(err);
});

If you don't supply socket.io with an http server, it will create one for you. So your code is actually creating two http servers, both trying to listen on the same port which fails with EADDRINUSE.
Instead, pass the httpServer as the first parameter to socket.io instead of a port number:
const socketIO = require("socket.io")(httpServer, { cors: { origin: "*" } });

It's happening because
const startServer = () => {
httpServer.listen(port);
console.log(`Listening on port ${port} 🚀`);
};
here already the address 3000 in use ... so you shouldn't pass the port:3000 into socketIO, better pass the httpServer, like :
const socketIO = require("socket.io") (httpServer, cors: { origin: "*" } });
socketIO.on("connection", (socket) => {
console.log("connected");
});

Related

CORS denying connection to socket io

I'm trying to use socket io to send and receive data in realtime, but when I run server and open the client page which connects using socket.io-client, I'm getting an error
I installed cors and used it like I've done multiple times before and I tried setting the headers of my response to Allow access from different origin but nothing worked.
this is the error I'm getting:
Access to XMLHttpRequest at 'http://localhost:5000/socket.io/?EIO=4&transport=polling&t=ONQYon3' from origin 'http://localhost:3000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
this is my server side code
require("dotenv").config();
const express = require("express");
const bodyParser = require("body-parser");
const mongoose = require("mongoose");
const cors = require("cors");
const { Server } = require("socket.io");
const app = express();
const server = require("http").Server(app);
const io = new Server(server);
app.use(bodyParser.json());
app.use(
cors({
origin: "*",
})
);
app.use((req, res, next) => {
res.setHeader("Access-Control-Allow-Origin", "*");
});
io.on("connection", (socket) => {
console.log("a user connected");
});
const port = process.env.PORT || 5000;
const url = process.env.MONGO_URI;
const start = async () => {
try {
await connectDB(url);
server.listen(port, (req, res) => {
console.log(`Server is listening on port ${port}`);
});
} catch (error) {
console.log(error);
}
};
start();
and all I'm doing on the frontend is using socket.io-client library to connect to the server in a react application like this.
import io from "socket.io-client";
const socket = io("http://localhost:5000");
any help is appreciated
You need to pass cors options to the io Server constructor itself.
E.g. instead of
const io = new Server(server);
you need
const io = new Server(server, {
cors: {
origin: '*',
}
});
I was able to solve the problem. it was because the client and server were running on different ports and even with cors defined socket.io needs its own cors setting in it in order to work, I changed it to this and it worked.
const io = require("socket.io")(5000, {
cors: {
origin: "*",
},
});

How can I get Socket.io to connect again?

In my Node.js backend I have the following code which is supposed to set up the Socket.io connection:
const express = require("express");
const app = express();
const { createServer } = require("http");
const httpServer = createServer(app);
const port = 3001;
const io = require("socket.io")(httpServer, { cors: { origin: "*" } });
io.on("connection", (socket) => {
console.log("Connected!");
socket.on("join-room", (id) => {
socket.join(id);
console.log(`user joined room ${id}`);
});
});
Previously this was working, but for some reason it isn't anymore. When I started my server today I wasn't able to get Connected! logged to the console, nor was user joined room logged to the console when that event was triggered. Is there something wrong with how I'm establishing this connection?

How to call ws WebSocket and wait for response in Express.js?

I have setup Nodejs to serve an HttpServer using ExpressJs. I also need to use ws WebSocket in order to connect to my device for fetching data.
My attempt is now this.
import express from 'express';
import cors from 'cors';
import http from 'http';
import { WebSocketServer } from 'ws';
const app = express();
app.use(cors());
//initialize a simple http server
const httpServer = http.createServer(app);
const wsServer = new WebSocketServer({ port: 7777});
wsServer.on('connection', function connection(ws, req) {
app.get('/', (req, res) => {
ws.send('{"msg":"getdata"}');
ws.on('message', function message(data) {
data = JSON.parse(data);
res.json(data);
});
});
//start our server
httpServer.listen(7778, () => {
console.log(`Server started on port ${httpServer.address().port} :)`);
});
});
The problem is that when the API is called more than once. An error code: 'ERR_HTTP_HEADERS_SENT' is thrown. I assume it is because the ws.on('message') is executed multiple times. So, I am trying to find a way to remove the listener but to no avail.
Is there any better way to do this? I just want to have a webserver that calls to another websocket in order to get data from a device.
For your code example to work, message on websocket must be sent after the / request is made. Because, before that, on message handler is not registered. Also, once handling the first request successfully, you cannot send a websocket message again. Because, when you do that, the res in the message handler is already completed. So, you will get ERR_HTTP_HEADERS_SENT. Thus proved :-)
So, your API calls must be like in the following pattern
/ Call #1
Websocket message #1
/ Call #2
Websocket message #2
If you do so, you will not get the ERR_HTTP_HEADERS_SENT error. Because, res is send once for every / request.
this will solve your error code: 'ERR_HTTP_HEADERS_SENT'
wsServer.on('connection', function connection(ws, req) {
app.get('/', (req, res) => {
//first This
ws.on('message', function message(data) {
data = JSON.parse(data);
res.json(data);
});
//then use this
ws.send('{"msg":"getdata"}');
});
//start our server
httpServer.listen(7778, () => {
console.log(`Server started on port ${httpServer.address().port} :)`);
});
});
var app = require('express')();
var http = require('http').Server(app);
var io = require('socket.io')(http);
var timeout = require('connect-timeout');
var uuid = require('uuidv4');
var _ = require('lodash');
app.use(timeout('10s'));
app.get('/', (req, res) => {
res.sendFile(__dirname + '/index.html');
});
let responses = []
io.on('connection', (socket) => {
socket.on('res', (e) => {
var obj = _.find(responses, r => r.id === e.id);
obj.res.send(e)
_.remove(responses, r => r.id === e.id);
})
})
app.get('/endpoint', (req, res) => {
const id = uuid()
io.emit('req', { id, ip: req.ip, header: req.headers, method: req.method });
responses.push({ id, res })
});
http.listen(3000);
If you want over multiple instance, you can use redis pub sub.

socket io client not connecting to server using ipv4 address

I'm having a problem with testing the connection when I use https://localhost:3000/ it connects successfully but I want to use socket Io client on a different device on android application to be precise I searched it up and turns out localhost wont work I have to connect using ipv4 address well I tried it but didnt work - like this http http://192.168.XX.XX:3000 for example so what is the problem why doesnt it connect please help
server code:
var cors = require("cors");
const express = require("express");
const app = express();
const port = process.env.PORT || 3000 ;
const server = app.listen(port, () => {
console.log(`started on ${port}`);
})
const io = require('socket.io')(server, {
cors: { origin: "*" }
});
io.on('connection', (socket) => {
console.log('a user connected');
socket.on('message', (message) => {
console.log(message);
io.emit('message', `${socket.id.substr(0,2)} said ${message}` );
});
});
require("dotenv").config();
app.use(express.json());
app.use(cors());
//routes setup
const homeGetRoute = require("./routes/test.js");
app.use("/home", homeGetRoute);
app.use(cors());

Should I create a route specific for SocketIO?

I'm a newbie to Socket.IO, I did the chat tutorial of the docs and the "homework" of the chat app to understand how it works, now I'm trying to connect an NodeJS server and a React App with a Socket. I've spent all day trying to do this, but I'm getting this error:
GET http://localhost:4000/?EIO=4&transport=polling&t=NYW26Ea 404 (Not Found)
The itention of my app is show an update of time, I'm using socket to update time on screen each one second.
Here's my Server.js file, and yes, it is pretty simple:
const express = require("express")
const http = require("http")
const socketIO = require("socket.io")
var cors = require('cors')
const PORT = 4000;
const routes = require("./routes/index")
const app = express()
app.use(cors())
app.use(routes)
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), 1000)
socket.on("disconnect", () => {
console.log("Client is disconnected")
clearInterval(interval)
})
})
const getApiAndEmit = socket => {
const response = new Date()
socket.emit("from-api", response)
}
app.listen(PORT, () => console.log(`Application up and running on ${PORT}`))
If I visit the route I created with express it works fine.
And here is my App.js file:
import React, { useState, useEffect } from "react";
import socketIOClient from "socket.io-client";
const ENDPOINT = "http://127.0.0.1:4000";
function App() {
const [response, setResponse] = useState("");
useEffect(() => {
const socket = socketIOClient(ENDPOINT);
socket.on("from-api", data => {
setResponse(data);
});
}, []);
return (
<p>
It's <time dateTime={response}>{response}</time>
</p>
);
}
export default App;
Should I create a route for SocketIO or what?
Should I create a route for SocketIO or what?
No. When you do this:
const io = socketIO(server)
The socket.io library already installed its own route handler for routes starting with /socket.io and any other routes it needs. You don't need to do that yourself.
You do, however, have a problem because you're hooking up socket.io to server that you never started.
When you do this:
app.listen(PORT, () => console.log(`Application up and running on ${PORT}`))
That creates a new http server and then calls .listen() on it and returns that new server. You will need to capture that server and hook up socket.io to it:
So, replace this:
const server = http.createServer(app)
const io = socketIO(server)
app.listen(PORT, () => console.log(`Application up and running on ${PORT}`))
With this:
const server = app.listen(PORT, () => console.log(`Application up and running on ${PORT}`))
const io = socketIO(server);
Then, you're creating and starting just one http server and hooking up both Express and socket.io to it. They can both share the same http server on the same port. Socket.io will use the route prefix /socket.io to distinguish its own routes and once a given socket.io connection has been established, that specific connection switches protocol to the webSocket protocol (with socket.io data frame on top of it) and is no longer using http any more.
Instead of:
app.listen(PORT, () => console.log(`Application up and running on ${PORT}`))
Use this:
server.listen(PORT, () => console.log(`Application up and running on ${PORT}`))
Reason: The server instance you are assigning to socketIO is not the same as the instance of server you are listening to.
With express you can pass the server instance like this:
var express = require('express');
var app = express();
...
...
...
var server = app.listen(PORT);
var io = require('socket.io').listen(server);
io.sockets.on('connection', function (socket) {
...
});
You can refer this: Express.js - app.listen vs server.listen

Categories

Resources