Should I create a route specific for SocketIO? - javascript

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

Related

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?

Address already in use with Socket.io in Express

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");
});

Listening for connections with socket.io not working

I'm using this code for my backend:
const express = require('express');
const app = express();
const socketIo = require("socket.io");
const io = socketIo(http);
io.on("connection", socket => {
console.log("New client connected");
socket.on("disconnect", () => console.log("Client disconnected"));
});
http.listen(3000, () => {
console.log('listening on *:3000');
});
When I run it, it outputs the message confirming it is listening. However, on a connection it does not send any messages to the console. I'm trying to listen for connections to a React app. I have tried using other code snippets for the connection function that also claim to work as I expected, however none that I have tried have worked, including the code in the official tutorial for socket.io.
Please can anyone help?
const express = require('express')
const app = express()
const PORT = 5000
// Get to http://localhost:5000
app.get("/", (request, response) => {
// Send back some data to the client
response.send("Hello world")
})
// Post to http://localhost:5000/getRandom
app.post("/getRandom", (req, res) => {
res.send(Math.random())
})
app.listen(PORT, () => console.log(`Server running on PORT ${PORT}`))
Instead of calling the parameters request and response, people use the short form of req and res
Now start this script and go to http://localhost:5000 and you will see "Hello world" in the HTML body. That's express, simple yet powerful :)

React/NodeJS won't speak via localhost in development

I'm working to setup a Node backend to feed data and communicate with ReactJS for my frontend. Ultimately I am developing new company software to replace our current Transportation System.
I utilize Amazon EC2 Ubuntu 16.04 - for my own reasons for my business - and I simply cannot get my ReactJS frontend with Socket.IO to communicate with my nodeJS backend with Socket.IO on http://localhost:4000/.
This is my App.js in my react frontend when it calls
import React, { Component } from 'react';
import logo from './logo.svg';
import ioClient from 'socket.io-client';
import './App.css';
var socket;
class App extends Component {
constructor() {
super();
this.state = {
endpoint: 'http://localhost:4000/'
};
socket = ioClient(this.state.endpoint);
}
This is my nodeJS index for the backend
const mysql = require('mysql');
const http = require('http');
const express = require('express');
const cors = require('cors');
const app = express();
const server = http.createServer(app);
const io = require('socket.io').listen(server);
app.use(cors());
app.get('/', (req, res) => {
res.send('Server running on port 4000')
});
const sqlCon = mysql.createConnection({
host: 'localhost',
user: 'admin-user',
password: 'admin-pass',
database: 'sample'
});
sqlCon.connect( (err) => {
if (err) throw err;
console.log('Connected!');
});
io.on('connection', (socket) => {
console.log('user connected');
});
server.listen(4000, "localhost", () => {
console.log('Node Server Running on 4000')
});
I can get it to communicate via my actual Public IP address, but not via localhost. I really don't want to expose my backend on my public IP address to communicate with it for all users. This has probably been asked before, but I honestly can't find a clear answer for it anywhere and I've been looking for 3 days now. Node has no problem executing, and like I said if I create the socket.io connection from the public IP, I can get it to communicate and as far as I can tell node has no problem running the rest of the script as it connects to mariaDB no problem.
This is the error I keep receiving in my Chrome console.
polling-xhr.js:271 GET http://localhost:4000/socket.io/?EIO=3&transport=polling&t=MvBS0bE net::ERR_CONNECTION_REFUSED
polling-xhr.js:271 GET http://localhost:4000/socket.io/?EIO=3&transport=polling&t=MvBS3H8 net::ERR_CONNECTION_REFUSED
I'm running React via npm start for the time being, so my localhost:3000 is being reverse proxied to nginx for my React frontend to be visible on my public EC2 IP via port 80.
Any help is appreciated!
It may be a cross origin request issue. Have you tried to enable CORS on your app. You can also use proxy in your react app package.json if you do not want to enable cors on your app.
In your react app package.json you can add
"proxy":"http://localhost:4000"
It's probably because the port you are using isn't available in the server-side when it's running.
Use the server-side port like this,
var port = process.env.PORT || 3000;
server.listen(port, "localhost", () => {
console.log('Node Server Running on 4000')
});
and on the client-side just connect to the app URL, like,
this.state = {
endpoint: '/'
};
socket = ioClient(this.state.endpoint);
Just clean up your server a bit. Take this guy run him from whatever terminal or ide you use to get your server going.
let startTime = Date.now();
const express = require('express');
const bodyParser = require('body-parser');
const compression = require('compression');
var cors = require('cors');
const app = express();
app.use(compression());
app.use(bodyParser.json({ limit: '32mb' }));
app.use(bodyParser.urlencoded({ limit: '32mb', extended: false }));
const http = require('http').Server(app);
const io = require('socket.io')(http);
app.use(cors({ origin: 'null' }));
const request = require('request');
const port = 4000;
let pm2InstanceNumber = parseInt(process.env.NODE_APP_INSTANCE) || 0;
http.listen(port + pm2InstanceNumber, err => {
if (err) {
console.error(err);
}
console.log('Listening http://localhost:%d in %s mode', port + pm2InstanceNumber);
console.log('Time to server start: ' + (Date.now() - startTime) / 1000.0 + ' seconds');
setTimeout(() => {
try {
process.send('ready');
} catch (e) {}
}, 2000);
app.get('/', (req, res) => {
res.send('Server running on port 4000')
});
});
or just run node filename.js to serve this guy up.

Adding socket.io to an existing Express project (with React on the front)

I have an existing project written in Express, where I've made a messaging system. Everything was working on POST/GET methods (to send and receive the messages).
I wanted to make them appear in real time, so I installed socket.io both on the client and server side. In my server.js I added these lines:
const http = require("http");
const io = require("socket.io");
const server = http.createServer();
const socket = io.listen(server);
and changed my app.listen(...) into server.listen(...).
Added also:
socket.on("connection", socket => {
console.log("New client connected");
socket.on('test', (test) => {
console.log('test-test')
});
socket.emit('hello', {hello:'hello!'});
socket.on("disconnect", () => console.log("Client disconnected"));
});
On the front part I put such code in the componentDidMount method:
const socket = socketIOClient();
socket.emit('test', {test:'test!'})
socket.on('hello', () => {
console.log('aaa')
})
Now I got 2 problems. Although the console.log() works correctly, I get an error on the React app:
WebSocket connection to 'ws://localhost:3000/sockjs-node/039/lmrt05dl/websocket' failed: WebSocket is closed before the connection is established.
Is that normal?
Also, when I change app.listen(...) into server.listen(...) in the server.js file, my routing stops working. All the POST and GET methods don't work, because the server is responding endlessly. Is that possible to use the socket.io just on a specific method in a specific routing file?
I keep my routes that way: app.use('/api/user', user); where user is a router file.
UPDATE:
full server.js require:
const express = require('express');
const mongoose = require('mongoose');
const dotenv = require('dotenv');
const bodyparser = require('body-parser');
const passport = require('passport');
const user = require('./routes/api/v1/User');
const company = require('./routes/api/v1/Company');
const http = require("http");
const io = require("socket.io");
const app = express();
dotenv.config();
app.use(passport.initialize());
require('./config/seed');
require('./config/passport')(passport);
const server = http.createServer();
const socket = io.listen(server);
You're not initializing server properly. Try making the following change
// const server = http.createServer();
const server = http.createServer(app);
and make sure you listen on server and not io
server.listen(PORT_GOES_HERE)
[UPDATE]
Working Example:
var app = require('express')();
var server = require('http').Server(app);
var io = require('socket.io')(server);
server.listen(80);
// WARNING: app.listen(80) will NOT work here!
// DO STUFF WITH EXPRESS SERVER
app.get('/', function (req, res) {
res.sendFile(__dirname + '/index.html');
});
io.on('connection', function (socket) {
socket.emit('news', { hello: 'world' });
socket.on('my other event', function (data) {
console.log(data);
});
});
For more details check this: https://socket.io/docs/

Categories

Resources