Create a REST API wrapper for Node.js TCP server - node.js

I have managed to create a TCP server using node.js which looks something like this.
const net = require('net');
const port = 7070;
const host = '127.0.0.1';
const server = net.createServer();
server.listen(port, host, () => {
console.log('TCP Server is running on port ' + port + '.');
});
I am wanting to create a http rest API wrapper around this. So that I can send messages from my TCP server to my TCP client. For example if I create a URL http://example.com/api/send-message and when I hit this URL it will trigger my TCP server to send a message.
I'm just so confused as to how I can even go about doing this as the TCP server and REST API server are on different ports. Please can anyone help

I managed to solve this by creating a node.js app that acts as a tcp client that talks to my node.js tcp server. In the client I integrated express. Express creates the API and then on each endpoint I created a TCP connection that communicates with my TCP server and then the response is sent back to my http API
const express = require('express')
const app = express()
const port = 3000;
const net = require('net');
const client = new net.Socket();
var tcpPort = 7070;
var tcpIP = '127.0.0.1';
app.get('/',function(req, res){
client.connect(tcpPort, tcpIP);
client.write('Hello world');
client.on('data', function(data) {
client.destroy();
res.send({hello:data.toString()});
});
});

Related

How to run NodeJs SocketIO on server (Centos 7)

I create app with nodejs socket io. It works clearly at localhost (port: 3000). But when i deploy it to my server in there i can run my app on 3000 port but client side throw timeout. How can i solve it?
var fs = require('fs');
var https = require('https');
var options = {
key: fs.readFileSync('ssl.my-key.key'),
cert: fs.readFileSync('ssl.my-cert.crt')
};
var server = https.createServer(options);
var io = require('socket.io').listen(server);
var port = 3000;
const database = require('./Database');
io.on('connection', (socket) => {
socket.on('message', async (msg) => {
// I do some action here.
});
socket.on('disconnect', (msg) => {
// some action in here too
});
});
server.listen(port, () => {
console.log('listening on *:' + port);
});
It seems like your issue is with port forwarding.
In order for your server to be publicly accessed, it needs to have all ports forwarded appropriately. Locally and on the router.
Check this link to learn more about how to port forward on linux: https://linuxacademy.com/guide/11630-internal-port-forwarding-on-linux-using-the-firewall/
And this to learn more about router port forwarding, but this will really depend on your router.
https://www.noip.com/support/knowledgebase/general-port-forwarding-guide/
However, I don't recommend you to take care of hosting on your own machine(s). I
suggest you use Heroku, you can op in for their free servers, you don't need to pay.
More about heroku and NodeJS: https://linuxacademy.com/guide/11630-internal-port-forwarding-on-linux-using-the-firewall/
let we debug your node js app.
1) add some logs on database connection, http.createserver, also where you have to check if not success then catch exception
2) you should have to open port on centOs before start your node js app
3) you should have test you with domain name or ip address
as per you comment you got connection timeout , you mean node js server trying to connect with port 3000 but node not able to connect and its throws error with connection timeout
also send your sample code of your main index file so we can investigate your problen
thanks.

ExpressJS Routes + Websockets - Share Port

I have an https expressjs server with websockets (using the 'ws' package). As far as I understand sockets and ports, I should be able to add a route alongside the websocket connections. The main use-case is so that the server can be curled (none of the ws curl requests I've seen online worked.)
Unfortunately I only have 1 port to use for the server and websockets. How can I set this up so that app and server can both listen on the same port?
I've seen a few comments on SO that indicates that it can be done, but no code examples, or it's for very different packages.
I'm using the 'ws' package: https://www.npmjs.com/package/ws
const port = 8888;
const http = require('http');
const https = require('https');
const express = require('express');
const websocket = require('ws');
const app = express();
app.use( express.static('public') );
app.get('/curl', (req, res) => res.send('Hello World')).listen( port );
const httpsServer = https.createServer( credentials, app );
const wss = new websocket.Server({ server: httpsServer });
httpsServer.listen( port, function listening(){
console.log( 'listening on ' + port );
});
Currently I get the "EADDRINUSE" error since I'm using the same port for two 'servers'.
FOLLOW-UP
Express app doesn't need to also listen if another server is.
To curl https, you have to provide the cert details, or use the '-k' (insecure) method.
Your code shows you trying to start two servers on the same port.
This line creates a new http server and attempts to start it on port 8888:
app.get('/curl', (req, res) => res.send('Hello World')).listen( port );
These lines create a new https server and attempt to start it on port 8888 also.
const httpsServer = https.createServer( credentials, app );
httpsServer.listen( port, function listening(){
console.log( 'listening on ' + port );
});
You cannot do that. If you just want one https server that works for both your web requests and your webSocket (a common way to do things), then change your code to this:
const port = 8888;
const https = require('https');
const express = require('express');
const websocket = require('ws');
const app = express();
app.use( express.static('public') );
app.get('/curl', (req, res) => res.send('Hello World'));
const httpsServer = https.createServer( credentials, app );
const wss = new websocket.Server({ server: httpsServer });
httpsServer.listen( port, function listening(){
console.log( 'listening on ' + port );
});
which just removes the .listen(port) that operates on the app object because that will create an http server and start it on the 8888 port.

Socket.io with Express, how does express app know what port to listen on?

I am pretty new to nodejs and very new to socket.io and express. I have some code that is working, but am having trouble understanding exactly why it's working.
My question for the below code is how does the express app know to listen on port 80? There's a server.listen. But there is no app.listen in the code. Yet app.post() readily accepts posted data.
Please consider the following code
var https = require('https');
var url = require('url');
var fs = require('fs');
var bodyParser = require('body-parser');
var express = require('express');
var app = express();
//var io = require('socket.io');
var zlib = require('zlib');
app.use(bodyParser.urlencoded({extended: true }));
var options = {
key: fs.readFileSync('my.key'),
cert: fs.readFileSync('my.crt')
};
var serverPort = 80;
var server = https.createServer(options, app);
var io = require('socket.io')(server);
// log when the server is ready
server.listen(serverPort, function() {
console.log('Web socket server up and running at port %s', serverPort);
// this prints 80, as expected
});
app.post('/api', function (req, res) {
// working code is in here that receives the post variables and responds
}
With Express, the app object is just a request handler for some http server. If you call app.listen(), then the app object will create an http server for you. But, if you have created your own http server (which your code example does), then the app object just becomes a request listener on that server with this line of your code:
var server = https.createServer(options, app);
That creates the http server and registers app as a request listener (so it sees all incoming requests). This allows the Express app object to then process the routes that are registered with it to server routes like app.get(...) or app.post(...).
And, the port for Express is the port for the http server so it's the port that was used when the http server was created. What's important to understand here is that Express is not its own server. It's just a request listener for some http server.
In your code example, your http server is set up for port 80 so that's the port being used and Express gets registered as a request handler on all those incoming http requests on that port.
If you look at the source code for app.listen(), you see this:
app.listen = function listen() {
var server = http.createServer(this);
return server.listen.apply(server, arguments);
};
All, it does is create an http server with the app object as a listener and then call .listen() on that new server.
the app does not have to know on which port to listen. Basically, server is your HTTP server binding which listens on port 80 in your example. var server = https.createServer(options, app); then tells the server to listen on port 80 for HTTP requests and forward them to your app. The app then does the routing stuff that links the function you sepcified with app.post(...) to a specific request URL (/api in this case).
TL;DR: The app does not need to listen, because the server is the only communication interface to the outside.

NodeJS and socket.io app on Heroku with 2 ports

My app has an express server listening on one port (process.env.PORT) and I also want a web socket using another port. I used to use Express 3 with this set-up:
var express = require('express'),
http = require('http'),
io = require('socket.io'),
app = express();
server = http.Server(app);
ioServer = io(server);
ioServer.on('connection', callback);
server.listen(process.env.PORT || 3000, function () {
console.log('App listening on ' + server.address().port);
});
The above code worked fine, as when creating ioServer, no specific port is required. However, after I switched to Express 4 and started using Heroku's WebSocket service, I had to specify a port like this:
var WebSocketServer = require('ws').Server,
port = 5000,
server = http.createServer(app);
server.listen(port);
var wss = new WebSocketServer({server: server});
wss.on('connection', callback);
app.listen(app.get('port'), function() {
console.log('Express server listening.'));
});
This new set-up never works because when I run the app on Heroku, I get an error complaining that the same port can't be used twice:
Error: listen EADDRINUSE :::40854
The set-up logic is essentially the same except for explicitly assigning a port in Express 4, so why did my code work with Express 3 but not Express 4? How should I fix this?
In your second code block, you can't call .listen() on both your server and on your app object. In this particular case (the way you've structured your code), you only want to call it on the server object, not on app.
This is the code from Heroku's dev page on this topic:
var WebSocketServer = require("ws").Server
var http = require("http")
var express = require("express")
var app = express()
var port = process.env.PORT || 5000
app.use(express.static(__dirname + "/"))
var server = http.createServer(app)
server.listen(port)
console.log("http server listening on %d", port)
var wss = new WebSocketServer({server: server})
console.log("websocket server created")
Also, your first code block is not running on two ports. As is usually the design for webSockets, a single port is used for both your web requests and your webSocket connections. The web server itself splits out the two types of connections based on the initial connection.

socket.io doesn't work on heroku

I'm new to socket.io and heroku.I wrote the simple chat system but when I publish that on Heroku it doesn't work.
app.js
var port = process.env.PORT || 3000;
var io = require('socket.io')(port);
// var url = require('url');
io.on('connection', function(socket,d) {
socket.on('sendMsg', function(data) {
console.log('SEND msg');
console.log(data);
io.emit('getMsg',data);
});
console.log(socket.handshake.query.id);
});
and in client :
<script src="http://chatserversm.herokuapp.com:3000/socket.io/socket.io.js"></script>
<script>
var socket = io('http://chatserversm.herokuapp.com:3000?id=2');
....
Where I was wrong ?
Your client attempts to connect to port 3000, but on Heroku process.env.PORT is set to 80.
Heroku only exposes port 80 (and 443 for SSL), so you will have to change your client to connect to that port.
Note that it should work just fine with an HTTP server on the same port.
Edit: here's what you should do.
First, you need your client to connect to the right port:
var socket = io('http://chatserversm.herokuapp.com:80?id=2');
Since port 80 is already implied, you can also write this as:
var socket = io('http://chatserversm.herokuapp.com?id=2');
Another similar issue is that you're trying to get socket.io.js from port 3000, so you also need to change to:
<script src="http://chatserversm.herokuapp.com/socket.io/socket.io.js"></script>

Resources