Socket.io keep connection up when server get refreshed / turned down - node.js

Premising I'm new to sockets, I'm trying to set up the first configuration on server (Node w/Express).
While doing so, I encountered an issue where nodemon crashes every time I save, by returning Error: listen EADDRINUSE: address already in use :::8080.
Here the server implementation:
import express from "express";
import cors from "cors";
import { Server, Socket } from "socket.io";
import { createServer } from "http";
import morgan from "morgan";
// App configuration
const app = express();
const server = createServer(app);
const io = new Server(server);
const port = process.env.PORT || 8080;
// Middlewares
app.use(cors());
app.use(express.json());
app.use(morgan("combined"));
// Socket connection
io.on("connect", (socket: Socket) => {
socket.send("test");
});
server.listen(port, () => {
console.log(`Server is up and running on ${process.env.NODE_ENV} - port ${port}`);
});
I would think that happens as the socket.io connection never get closed / disconnected, leaving the server instance up listening.
I had a look around and found many q/a that were suggesting commands to find and kill the process, but I'd need a solution able to disconnect the socket automatically every time the express server gets turned down.
I tried the following:
io.on("disconnect", () => {
io.sockets.disconnect();
}
As suggested here, but TS complains about io.sockets.disconnect() with a Property 'disconnect' does not exist on type 'Namespace<DefaultEventsMap, DefaultEventsMap>'.ts(2339).
Any idea how this should be tackled?

I think there may be an issue in socket io initialization. Can you try this type of initialization showed at https://socket.io/get-started/chat#Integrating-Socket-IO:
const express = require('express');
const app = express();
const http = require('http');
const server = http.createServer(app);
const io = require('socket.io')(server);
app.get('/', (req, res) => {
res.sendFile(__dirname + '/index.html');
});
io.on('connection', (socket) => {
console.log('a user connected');
});
server.listen(3000, () => {
console.log('listening on *:3000');
});
So basically pass server object to the default import from socket io like this(right now, you are using "Server" inside socket.io ):
import express from "express";
import cors from "cors";
import ioDefault, { Server, Socket } from "socket.io";
import { createServer } from "http";
import morgan from "morgan";
// App configuration
const app = express();
const server = createServer(app);
const io = ioDefault(server);
const port = process.env.PORT || 8080;
// Middlewares
app.use(cors());
app.use(express.json());
app.use(morgan("combined"));
// ...
UPDATE:
The issue was another server running on the same port. To check which process is running on a specific port you can run
netstat -anpe | grep "8080" | grep "LISTEN"
if netstat is not installed run sudo apt install net-tools in debian based systems(ubuntu, fedora and others)
you can then kill it with its pid:
kill -9 5454

Related

Debian server, Node js Port 3000 listening But cant access via browser

On my debian server, I installed node and then started node server on port 3000. The server is running, but it isn't visible from the browser
Now when I try to get it running via my domain or via my ip(for example xx.xxx.xx.xx:3000) or my domain (my-domain.com:3000) in both cases it doesn't work. I think I don't quite get the concept and I tried to search for a billion different things, but I can't find the solution to my problem. Could someone tell me, if I need to setup something else, too?
My server js code is
const express = require('express');
const app = express();
const http = require('http');
const server = http.createServer(app);
const { Server } = require("socket.io");
const io = new Server(server);
server.listen(3000, () => {
console.log('listening on *:3000');
});
io.on('connection', function (socket) {
socket.on( 'new_message', function( data ) {
io.sockets.emit( 'new_message', {
message: data.message,
date: data.date,
msgcount: data.msgcount
});
});
});
Error i got
You need to listen for GET requests in order to respond to them.
Try adding something like:
app.get('/', function (req, res) {
res.send('GET request test.')
})
In your case make sure you add the route before passing the app to the http.createServer() method, or otherwise just use something like app.listen(3000).
More info in the docs: https://expressjs.com/en/guide/routing.html
why are you using express and http both packages.
you can run server by either of them.
and then add a get route for it.
import { createServer } from "http";
import { Server } from "socket.io";
const httpServer = createServer();
const io = new Server(httpServer, {
// ...
});
io.on("connection", (socket) => {
// ...
});
httpServer.listen(3000);
I hope this will work!

Quasar application cannot connect to heroku socket.io server

I am trying to connect my quasar application to a socket.io express server hosted on heroku.
The problem is that every time I try to connect, the browser says the request is pending and on the backend I never receive the message of connection.
This is my backend code
const express = require('express');
const app = express();
const PORT = process.env.PORTA || 3000;
const server = app
.use((req, res) => {})
.listen(PORT, () => console.log(`Server is running on port ${PORT}...`));
const io = require('socket.io')(server, {
cors: {
origin: '*',
credentials: true
}
});
io.on('connection', socket => {
console.log('Connected: ' + socket.id);
});
And this is the connection in a boot file in quasar (vue.js) with socket.io extended
import Vue from 'vue'
import VueSocketIOExt from 'vue-socket.io-extended';
import { io } from 'socket.io-client';
const socket = io(URL_CONNECTION);
Vue.use(VueSocketIOExt, socket);
As you can see on the backend I have a console.log to see the id of the connected client. If I try this locally in my pc it works fine and I get the socket id, but on heroku the client doesn't connect without giving me any error.
I found a way to do this. I just removed the custom port I inserted in the server and I put the default (process.env.PORT) and then I connected from the client giving the port 80.
Now, I don't know why, but it's working.

Run Rest And Socket in Same Server in Node.js

This is my app.js and I want to perform both (Socket/Rest) But When I am emitting something from my client the socket is not connecting though it's showing me 101 Status in chrome ws. Can anyone help me out with what's wrong with this code?
here is my app.js
const express = require("express");
const app = express();
const indexRouter = require("./routes/index");
const apiRouter = require("./routes/api");
var server = require('http').createServer(app);
// var memcached = require('memcached');
// var mmc = new memcached('localhost:1121', {retries:10,retry:10000,remove:true});
var io = require('socket.io')(server);
const port = process.env.PORT || 3000;
const cors = require("cors");
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
app.use(cors());
app.use("/", indexRouter);
app.use("/api", apiRouter);
require("./app/router/login.router")(app);
require("./app/router/match.router")(app);
require("./app/router/competetion.router")(app);
server.listen(port,() => {
var host = server.address().address
var port = server.address().port
console.log(`Admin listening on port ${port}!`);
});
io.on('connection', (socket) => {
console.log('12---------12');
socket.on("test" , (data) => {
console.log('test', data);
})
});
// -- # socket manual --
// -- # socket ends ---
When I am emitting something its showing 101 status but nothing emitting at all
Thanks!
when considering the only problem is connecting to socket io, your code should establish a bi directional connection between the client and the server, and it does.
The 101 message means switching protocols
so if you emit a message on event named test your server will catch it.
the problem is in your client side, try any ready to use tools like this or anything else to independently test your socket io server

React and Express - Error during WebSocket handshake on localhost

I'm having trouble setting up a WebSocket connection using socket.io on my localhost. I'm using express on the server side and React on the client side.
I get the following message whenever I try to open a connection:
WebSocket connection to 'ws://localhost:5000/socket.io/?EIO=4&transport=websocket' failed: Error during WebSocket handshake: Unexpected response code: 404
I've seen some people having similar issues related to nginx or other web servers, but my problem is happening on localhost, which is why I am asking this question
Server-side code (I am using modules for the import, and I would like to keep it that way)
import express from 'express';
import bodyParser from 'body-parser';
import cors from 'cors';
import { createServer } from 'http';
import * as socketio from 'socket.io';
const app = express();
app.use(bodyParser.json({ limit: '30mb', extended: true }));
app.use(bodyParser.urlencoded({ limit: '30mb', extended: true }));
app.use(cors());
app.use('/foo', bar);
const server = createServer(app)
const io = new socketio.Server(server);
io.on('connect', socket => {...});
const PORT = process.env.PORT || 5000
app.listen(PORT, () => console.log(`Server running on port ${PORT}`)))
Client-side code (I've already tried passing different values to the "transports" array but it did not help) :
import io from 'socket.io-client';
let socket;
const Component = () => {
...
const { id } = useParams();
const ENDPOINT = 'ws://localhost:5000';
useEffect(() => {
socket = io(ENDPOINT, { transports: ['websocket', 'polling', 'flashsocket'] });
return () => {
socket.emit('disconnect');
socket.off();
}
}, [ENDPOINT, id]);
return (...)
})
Change last line of Server side code to
server.listen(PORT, () => console.log(`Server running on port ${PORT}`));

getting 404 error repeatedly when integrating socket.io with Mean

I'm trying to automatically refresh list when a change is happend in database. so far i'm getting this error in console reapeatedly
so can't find the bug.
app.js
//importing modules
const express = require('express');
const http = require('http');
const path = require('path');
const mongoose = require('mongoose');
const bodyParser = require('body-parser');
const cors = require('cors');
const socketIO = require('socket.io');
const errorHandler = require('./_helpers/error-handler');
const app =express();
const notice = require('./controllers/noticeController');
const employee = require('./controllers/employeeController');
const users = require('./users/users.controller');
//connect mongoDb
//on connection
mongoose.connection.on('connected',()=>{
console.log('Connected to database');
});
mongoose.connection.on('error',(err)=>{
if(err){
console.log('Error in Database Connection '+err);
}
});
const port = 3000;
//adding middleware
app.use(cors());
//body-parser
app.use(bodyParser.json());
//routes
app.use('/api', notice);
app.use('/api', employee);
app.use('/users', require('./users/users.controller'));
app.use(errorHandler);
const server = http.createServer(app);
const io = socketIO(server);
app.set('io',io);
//static files
app.use(express.static(path.join(__dirname, 'public')));
app.listen(port,()=>{
console.log('Server started at port: '+port);
});
and here is the post and get API with socket.io
noticeController.js
//retrieving notice list
router.get('/notices/get',(req,res)=>{
notice.find({}).then((notices)=>{
res.send(notices)
});
});
//add notice
router.post('/notice/add',(req,res,next)=>{
const io = req.app.get('io');
let newNotice = new notice({
title : req.body.title,
description : req.body.description,
image : req.body.image
});
newNotice.save().then(()=>{
io.emit('newNoticeAdded');
});
});
so can anyone help with this matter?
to client side. I have use socket-io-client package.
ts file.
ngOnInit(): void {
this.socket.on('newNoticeAdded',()=>{
this.noticeService.getNotices()
.subscribe(notices => {
this.notices = notices;
});
});
}
notices is the list that want to update automatically on change.
Right away, I could spot something fishy with your code. Look at the following lines:
const server = http.createServer(app);
const io = socketIO(server);
app.set('io', io);
//static files
app.use(express.static(path.join(__dirname, 'public')));
app.listen(port, ()=>{
console.log('Server started at port: '+ port);
});
What is happening here? Well, let's analyze:
You are creating a HTTP using http.createServer(app), then,
You are passing the server to the socketIO() constructor, after that,
You set up some static file routes for your app, finally,
You call app.listen on your express app to start the express app.
What is missing here? You never called server.listen on your HTTP server!
Why is that important, you ask? Because your Socket.IO server is bound to your HTTP server, not your express app. Since you only told your express app to start accepting connections, your Socket.IO server hasn't been started.
To solve this, you could just call server.listen on your HTTP server instead of you express app, like this:
const server = http.createServer(app);
const io = socketIO(server);
app.set('io', io);
//static files
app.use(express.static(path.join(__dirname, 'public')));
// Notice we called the listen function on your HTTP server
// instead of your express app. Your express app will still work
// because you passed your app to the http.createServer method
server.listen(port, ()=>{
console.log('Server started at port: '+ port);
});
Oh, and also, you should make sure your client-side code is connecting to the correct address. Like, make sure you connect to the address that your server is listening on, not some other address. I'm saying this because your error pictures show that you were trying to connect to port 4200 instead of 3000, which is what your server is listening on.
EDIT Since I saw you weren't sure how to connect your client to the same port as your server is running on, here's some code to help you out.
// You could just do this, and the socket.io client
// will connect to the ```window.location```, which
// is usually what you want.
// This is good because you don't hard-code the URL
// into your code, making it easier for you to put the
// script into production.
const socket = io();
// You could also do ```io.connect```, but BEWARE,
// you have to change the URL that the socket.io client
// connects to manually, so that's why I prefer the above
// method.
const socket2 = io.connect("http://localhost:3000");
You can see the default behaviour of the io() function here
Hope this helps.
You need to use the same port on both sides. My client side typescript service (server is using port 8090):
import { Injectable } from '#angular/core';
// rxjs
import { Observable } from 'rxjs';
// other
import { NGXLogger } from 'ngx-logger';
import { Event } from '../model/event';
import { environment } from '../../../environments/environment';
import * as socketIo from 'socket.io-client';
export let SERVER: string = "";
if (environment.production) {
SERVER = 'http://10.1.1.7:8090'; // EDS Server
} else {
SERVER = 'http://10.1.1.194:8090'; // Portalogic PC
//SERVER = "http://" + window.location.hostname + ":8090";
}
#Injectable({
providedIn: "root"
})
export class SocketService {
debug: boolean = true;
private socket: any;
constructor(
private logger: NGXLogger,
) { }
public initSocket(): void {
if (this.debug) {
this.logger.debug("initialize websocket at " + SERVER);
}
this.socket = socketIo(SERVER);
}
public closeSocket(): void {
this.socket.close();
}
public sendEvent(event: Event, data?: Object): void {
if (this.debug) {
this.logger.debug("sendEvent >> event = " + event.toString() + "; data = " + JSON.stringify(data));
}
this.socket.emit(event.toString(), data);
}
public onEvent(event: Event): Observable<Event> {
return new Observable<Event>(observer => {
this.socket.on(event, (data: any) => observer.next(data));
});
}
}
I call initIoConnection from app.component.ts then subscribe to onEvent events.

Resources