Test the functionality of keepalive in a Node.js TCP socket - node.js

I've been testing the functionality of keepalive in Node.js TCP sockets. It seems that I'm missing something here!
Here is my server code:
var net = require('net');
function accept(socket) {
socket.setKeepAlive(false);
socket.on('data', function(data) {
console.log("DATA");
console.log(data);
});
socket.on('error', function (e) {
console.log("ERROR");
console.log(e);
});
socket.on('close', function () {
console.log("CLOSE");
});
socket.on('end', function () {
console.log("END");
});
socket.write("Hi");
}
var server = net.createServer(accept);
server.listen(8011);
And it is my client code:
var net = require('net');
var socket = new net.Socket();
socket.setKeepAlive(false);
socket.on('data', function(data) {
console.log("DATA");
socket.write(data);
});
socket.on('error', function (e) {
console.log("ERROR");
console.log(e);
});
socket.on('close', function () {
console.log("CLOSE");
});
socket.on('end', function () {
console.log("END");
});
socket.connect(8011, '127.0.0.1');
Why does the server (or the client) not close the connection even if no data has been sent or received for a long time (120 sec)?
I'm using Node.js version 0.10.5!

Because keep-alive works at a lower level. It sends a check packet without any data payload and if there's no answer, then the connection is considered broken.
Try doing the same, but unplug your Ethernet cable from one of the machines.
Edit 0:
Sorry, misread your code a bit.
TCP keep-alive feature is often called "dead peer detection". Read about its mechanics, for example, here. With keep-alive disabled there's nothing in TCP itself that would force the connection to be closed after any inactivity timeout. It's intermediate devices like NAT-ing routers that may expire state and break your connection, not the communicating ends themselves.

Related

NodeJS Net module doesn't send message to server

I am using NodeJS Net module to send a TCP message to a server.
I studied some code on the internet and end up with this simple code:
var enviarMensagemTCP = function (mensagem, port, host) {
const Net = require("net");
const client = Net.createConnection({ port: port, host: host });
console.log(`enviar mensagem TCP para ${host}:${port}`);
client.on("connect", function () {
client.write(`${mensagem}`, () => {
client.destroy();
});
});
client.on("error", function (error) {
client.destroy();
});
};
My client is successfully connection to the server, however no message is read by the server I wrote in delphi.
IDPessoa := AContext.Connection.Socket.ReadLn;
The problem was simple, I was trying to read the line in the server, however, my client was not sending the data line by line.
Just added a line breaking after the message fixed the issue.
client.write(`${mensagem}\r\n`, () => {
client.destroy();
});

How to pass a message while connecting to websocket server on node

I have this code here -
const wss = new SocketServer({ express() });
wss.on('connection', ws => {
console.log('Client connected');
ws.on('message', msg => {
console.log('received: %s', msg);
});
ws.on('close', () => console.log('Client disconnected'));
});
Now there are some problems, A D-Dos attack can crash my server.
Is there a way to check a token or something before allowing a stranger to connect to the websocket? Also the socket will be on another domain so cookies won't work.
Or is there a way to disconnect a user if he has not sent the authentication token after connecting.
If it were running and allowing everyone to connect indefinitely, then that's a security risk. Server can be brought down easily.
With Socket.io possible a setup like you need, see Authenticating socket io connections
Otherwise you must implement it by your own, but you should follow some standards. The first ugly-hand-made solution that i can think is something like:
wss.on('connection', ws => {
console.log('Client connected');
isAuthenticated = false
ws.on('message', msg => {
if (!isAuthenticated ) {
// check if message is a token
// else comunicates back the error
}
console.log('received: %s', msg);
});
ws.on('close', () => console.log('Client disconnected'));
});
For the DDos attack, if they have a token they can spam infinite requests: same thing, you should count the incoming massage rate by your own and implementing something like a Throttling policy.

Socket.io communicating from server to client not happening

i am trying to do a very simple real time notification with socket.io. for some reason i can't receive data or fire the event from server to client but from client to server yes. let me show my code:
Client Side
ngOnInit() {
this.socket.on('connect', function (res: any) {
console.log('Socket.io is connected on client side!'); // it shows on client console
});
this.socket.on('alarmsreceived', function (res: any) {
console.log(res + ' i am here now'); // is not firing
});
}
// this method fires from a click button
objectStatus = () => {
this.socket.emit('alarmsystem', 'i am client going to server');
}
Server
var io = require('socket.io').listen(server);
var connections = [];
io.of('/api/v1/monitoring').on('connect', function(socket){
connections.push(socket);
console.log('Connected %s sockets', connections.length); // i see connection on cmd
socket.on('disconnect', function() {
connections.splice(connections.indexOf(socket), 1);
console.log('Connected %s sockets', connections.length);
});
socket.on('alarmsystem', function(res) {
console.log(res); // this shows me the message from client
io.sockets.emit('alarmsreceived', 'I am server heading to client');
});
})
it seems pretty straight forward, but not firing the client event. Can someone help me what i am doing wrong here? Thanks in advance

NodeJS: TCP socket server only returns data the first time

I'm attempting to write a small relay script in node.js that listens for incoming TCP connections on a local socket, and when it gets one, forwards the traffic to a 3rd party. It must also take any returned data from that 3rd party and send it back to the original local socket. I've tried code like http://delog.wordpress.com/2011/07/19/a-tcp-relay-mechanism-with-node-js/ and it does work, but it requires the sender be a server that is listening on a socket itself, and my utility is intended to work with any program that tries to create an outbound TCP connection. Unfortunately, the problem I'm running into is that everything works great the first time with the client sending the data to the "router" program, and the router forwarding it to another server, and then returning the data from the client. However, when the client program ends or is terminated and attempts to reconnect, I get this:
events.js:72
throw er; // Unhandled 'error' event
^
Error: This socket has been ended by the other party
at Socket.writeAfterFIN [as write] (net.js:275:12)
at Socket.<anonymous> (/root/tcp_loop.js:37:17)
at Socket.emit (events.js:117:20)
at Socket.<anonymous> (_stream_readable.js:748:14)
at Socket.emit (events.js:92:17)
at emitReadable_ (_stream_readable.js:410:10)
at emitReadable (_stream_readable.js:406:5)
at readableAddChunk (_stream_readable.js:168:9)
at Socket.Readable.push (_stream_readable.js:130:10)
at TCP.onread (net.js:528:21)
I ripped out all of the logic and distilled the test case into a small bit of code: one server that acts as both the router (listening on port 8124) as well as the "remote" server (on port 9999), though my testing indicates it makes no difference weather the remote server is on the same machine, on the Internet, etc. Here is the server code:
var net = require('net'),
util = require('util')
;
// The loop_server simulates a remote service.
// The error occurs whether using it here, or actually forwarding
// the data to a remote host.
var loop_server = net.createServer(function(loop) {
console.log("Loop server connected");
loop.on("end", function() {
console.log("Loop server disconnected");
});
loop.on("data", function(data) {
console.log("Loop got data: " + data);
loop.write(data);
});
}).listen(9999, function() {
console.log("Loop server bound");
});
var remote_socket = net.connect(9999, function() {
console.log("Remote connected");
var local_server = net.createServer(function(local_socket) { //'connection' listener
console.log('Local server connected');
local_socket.on('end', function() {
console.log('Local server disconnected');
// local_socket.destroy();
});
local_socket.on('data', function(ldata) {
console.log("Local socket got data: " + ldata);
remote_socket.write(ldata);
});
remote_socket.on('data', function(rdata) {
console.log("Remote socket got data: " + rdata);
local_socket.write(rdata);
});
local_socket.write('hello\r\n');
}).listen(8124, function() { //'listening' listener
console.log('Local server bound');
});
}); // remote_socket
The thing that's failing is the local_socket.write(rdata); in the remote_socket.on('data', ... handler. It works the first time the router is started and the client connects, but never again.
For reference, here is the code for the little client app that I've been using. I get the same result with a perl script, telnet, etc.:
var net = require('net');
var client = new net.Socket();
client.connect(8124, function() {
console.log('CONNECTED TO: localhost:8124');
client.write('Single text message from the client app');
});
client.on('data', function(data) {
console.log('DATA: ' + data);
});
client.on('close', function() {
sconsole.log('Connection closed');
});
Any insight would be greatly appreciated. I feel like I must be missing something extremely simple here...
Update:
Nitzin's solution below is a better way to do this, but in my particular example below, the solution is to remove old remote_socket.on('data') listeners before creating new ones, e.g.:
var remote_socket = net.connect(9999, function() {
console.log("Remote connected");
var local_server = net.createServer(function(local_socket) { //'connection' listener
console.log('Local server connected');
remote_socket.removeAllListeners('data');
...
remote_socket.on('data', function(rdata) {
console.log("Remote socket got data: " + rdata);
local_socket.write(rdata);
});
You should not destroy the socket. It closes both ends of the socket. You should only .end() it, which closes your writing end.
EDIT
Destroying the socket is bad, as I originally wrote, but your real problem is something completely different: you got your proxy (what you call "local") and echo (what you call "remote") servers backwards: the proxy server should make a new connection to the echo server for each new connection the proxy server gets, not the other way around as you have it now.
The only end() needed is in the client, to let the server know you're done writing.
Here is client.js:
var net = require('net');
var client = new net.Socket();
client.connect(8124, function() {
console.log('CLIENT: CONNECTED: localhost:8124');
client.write('single text message from the client app');
client.end();
});
client.on('data', function(data) {
console.log('CLIENT: GOT DATA: ' + data);
});
client.on('close', function() {
console.log('CLIENT: CONNECTION CLOSED');
});
And here is servers.js:
var net = require('net'),
util = require('util');
net.createServer(function(conn) {
console.log('ECHO_SERVER: CONN: new connection');
conn.on('end', function() {
console.log('ECHO_SERVER: CONN: disconnected');
});
conn.on('data', function(data) {
console.log('ECHO_SERVER: CONN: GOT DATA: ' + data);
conn.write(data);
});
}).listen(9999, function() {
console.log('ECHO_SERVER STARTED');
});
net.createServer(function(conn) {
console.log('PROXY_SERVER: CONN: new connection');
var remote = net.connect(9999, function() {
console.log('PROXY_SERVER: CONNECTED TO ECHO_SERVER');
conn.on('end', function() {
console.log('PROXY_SERVER: CONN: disconnected');
remote.end();
});
conn.on('data', function(data) {
console.log('PROXY_SERVER: CONN: GOT DATA FOR ECHO_SERVER: ' + data);
remote.write(data);
});
remote.on('data', function(data) {
console.log('PROXY_SERVER: CONN: GOT DATA FROM ECHO_SERVER: ' + data);
conn.write(data);
});
});
}).listen(8124, function() {
console.log('PROXY_SERVER STARTED');
});
As you can see, for each conn to the proxy server, there is a new remote going to the echo server.

Node.js: client doesn't die when TCP connection closes

I built a simple TCP server and a simple TCP client in Node.js
Now, when the client sends "exit" to the server, the connection is successfully closed. The server deletes the socket from its sockets list and sends "Bye bye!" to the client.
The connection on the client is closed as well but the app is still waiting for other inputs, so it doesn't die and I'm forced to type CTRL+C.
I tried adding process.exit() after connection closes but it doesn't work:
CLIENT CODE:
var net = require('net'),
config = require(__dirname + '/config.json'),
connection = net.createConnection(config.port, config.host);
connection.setEncoding('utf8');
connection.on('connect', function () {
console.log('Connected');
});
connection.on('error', function (err) {
console.error(err);
});
connection.on('data', function (data) {
console.log('ยป ' + data);
});
connection.on('close', function() {
console.log('Connection closed');
});
process.stdin.on('data', function (data) {
if ((new String(data)).toLowerCase() === 'exit') {
connection.end();
process.exit();
}
else {
connection.write(data);
}
});
process.stdin.resume();
SERVER CODE:
var server = require('net').createServer(),
config = require(__dirname + '/config.json'),
sockets = [];
server.on('connection', function (socket) {
socket.setEncoding('UTF-8');
socket.on('data', function (data) {
console.log('Received data: ' + data);
if (data.trim().toLowerCase() === 'exit') {
socket.write("Bye bye!\n");
socket.end();
}
else {
sockets.forEach(function (client) {
if (client && client != socket) {
client.write(data);
}
});
}
});
socket.on('close', function () {
console.log('Connection closed');
sockets.splice(sockets.indexOf(socket), 1);
console.info('Sockets connected: ' + sockets.length);
});
sockets.push(socket);
});
server.on('listening', function () {
console.log('Server listening');
});
server.on('close', function () {
console.log('Server is now closed');
});
server.on('error', function (err) {
console.log('error:', err);
});
server.listen(config.port);
EDIT:
I added a client connection "on close" event handler. So, the string "Connection closed" is now printed by the server and by the client too.
I think you're looking for this: socket.unref().
From Node.js documentation (https://nodejs.org/api/net.html#net_socket_unref):
socket.unref()#
Calling unref on a socket will allow the program to exit if this is the only active socket in the event system. If the socket is already unrefd calling unref again will have no effect.
Some time ago when improving the tests suite for node-cubrid module, I had encountered the same problem. After all tests have passed, nodeunit process didn't quit because node-cubrid was using connection.end() to close the client socket when timeout occurs, just like you did.
Then I replaced connection.end() with connection.destroy(), a cleaner way to ensure the socket is really closed without actually terminating the running process, which, I think, is a better solution than the above suggested process.exit(). So, in your client code context, I would do:
process.stdin.on('data', function (data) {
if ((new String(data)).toLowerCase() === 'exit') {
connection.destroy();
}
else {
connection.write(data);
}
});
According to Node.js documentation:
socket.destroy()
Ensures that no more I/O activity happens on this socket. Only necessary in case of errors (parse error or so).
I doubt that if ((new String(data)).toLowerCase() === 'exit') is succeeding because data most likely has a trailing newline (in your server, you trim() before doing the comparison, but not in the client).
If that's fixed, you've got a logic problem: when getting "exit" you close the connection without sending "exit" to the server, so the server code that looks for "exit" will never execute.
You have to put the process.exit() instruction only on the last event handler. So, in this case you have to put it inside the client connection "on close" event handler:
CLIENT:
connection.on('close', function() {
console.log('Connection closed');
process.exit();
});
Try with Event: 'close' in the server:
http://nodejs.org/api/net.html#net_event_close

Resources