How to distinguish between node socket server / client packets on data event? - node.js

In node, when you create a socket server and connect to it with a client, the write function triggers the data event, but it seems there is no way to distinguish the source of the traffic (other than adding your own IDs/headers to each sent buffer).
For example, this is the output "server says hello" from the server.write, and then all of the "n client msg" are from client.write, and they all come out in on('data', fn):
➜ sockets node client.js
client connected to server!
client data: server says hello
client data: 1 client msg!
client data: 2 client msg!
client data: 3 client msg!
client data: 4 client msg!
Is there a correct way to distinguish the source of the data on a socket?
The code for a simple client:
// client.js
var net = require('net');
var split = require('split');
var client = net.connect({
port: 8124
}, function() {
//'connect' listener
console.log('client connected to server!');
client.write('1 client msg!\r\n');
client.write('2 client msg!\r\n');
client.write('3 client msg!\r\n');
client.write('4 client msg!\r\n');
});
client.on('end', function() {
console.log('client disconnected from server');
});
var stream = client.pipe(split());
stream.on('data', function(data) {
console.log("client data: " + data.toString());
});
and the code for the server
// server.js
var net = require('net');
var split = require('split');
var server = net.createServer(function(c) { //'connection' listener
console.log('client connected');
c.on('end', function() {
console.log('client disconnected');
});
c.write('server says hello\r\n');
c.pipe(c);
var stream = c.pipe(split());
stream.on('data', function(data) {
console.log("client data: " + data.toString());
});
});
server.listen(8124, function() { //'listening' listener
console.log('server bound');
});

The source of the traffic is the server.
If you're wanting to know whether it's data being echoed back to the client by the server, you will have to come up with your own protocol for denoting that.
For example, the server could respond with newline-delimited JSON data that is prefixed by a special byte that indicates whether it's an echo or an "original" response (or any other kind of "type" value you want to have). Then the client reads a line in, checks the first byte value to know if it's an echo or not, then JSON.parse()s the rest of the line after the first byte.

You can distinguish each client with:
c.name = c.remoteAddress + ":" + c.remotePort;
c.on('data', function(data) {
console.log('data ' + data + ' from ' + c.name);
});

Related

How to connect multiple socket clients nodejs

Scenario is i have a server where socket(1) runs i have one more server where socket(2) client connects to socket(1)
I have one browser socket which connects to socket(1)
Idea is to do request from browser and bring data from socket(2) server
Not sure how to difference between socket clients as all the sockets are similar to socket(1)
Ideally there will be multiple browser sockets and multiple socket(2) clients
Browser sockets can make request to any of the socket(2) clients
How to implement it using nodejs socket.io
Server
socket.on('action', (action) => {
if(action.type === 'server/hello'){
io.sockets.emit('broadcast',{ description: clients + ' clients connected!'});
console.log('Got hello data!', action.data);
}
});
Browser client
var socket = io.connect('localhost:3000', {reconnect: true});
socket.on('connect', function(data) {
socket.emit('joined', 'Hello World from client this is client plxx');
});
socket.on('response2', function(data) {
console.log("got it ", data);
$('#messages').append($('<li>').text(JSON.stringify(data)));
});
Server client
var io = require('socket.io-client');
var socket = io.connect('http://localhost:3000', {reconnect: true});
socket.on('broadcast', function (t) {
socket.emit("data", {data: 32})
console.log('broadcast! my host is est');
});
i should be able to communicate between socket clients
What I understood from your question is: you need to differentiate between sockets from different clients.
To solve that I would suggest simply emitting the socket source from the client on connect.
And on the server split the sockets into two lists.
Example:
Server
const BROWSER_CLIENTS = {};
const SERVER_CLIENTS = {};
io.on("connection", socket => {
socket.on("source", payload => {
if (payload == "browser")
BROWSER_CLIENTS[socket.id] = socket;
else if (payload == "server")
SERVER_CLIENTS[socket.id] = socket;
});
socket.on("disconnect", () => {
delete BROWSER_CLIENTS[socket.id];
delete SERVER_CLIENTS[socket.id];
});
});
Browser Client
socket.on("connect", () => {
socket.emit("source", "browser");
});
Server Client
socket.on("connect", () => {
socket.emit("source", "server");
});
Now when you receive an event you can detect from which source it originated. And if you need to send to all sockets of one type of clients you can simply do this:
Server
for (let i in BROWSER_CLIENTS)
BROWSER_CLIENTS[i].emit("Hello Browsers")
for (let i in SERVER_CLIENTS)
SERVER_CLIENTS[i].emit("Hello Servers")
EDIT: I found this link and thought you could make use of it. Socket.io Rooms

Usernames in a UDP chat server with NodeJS

I'm setting up a simple chat server with NodeJS that only uses a server and client. It works, and I can open up multiple client windows on the same machine, but now I need a bit more.
I would like to:
Give each client the option to set usernames
Have a client request current time from server
Action commands like "/me punches the warlock" that the server shows others as "User punches the warlock"
This sounds like a quick days work, but I just started looking at UDP and I can't quite find any examples online other than a generic server/client thing that sends and gets messages. How would I go about those tasks?
Code:
Server.js:
var dgram = require('dgram'); //import datagram to get everything needed for UDP
var PORT = 22222;
var CLIENT_PORT = 2223;
// An IP address that's reserved on each network
// Gets sent to the server
var ADDRESS = "-"; //dont want to show my IP :)
var sock = dgram.createSocket({reuseAddr: true, type: 'udp4'}); //can now open multiple clients
var current_time = Date.now(); //?
function sendMessage(data) {
sock.send(data, 0, data.length, PORT, ADDRESS, function(err){
if(err){
throw err;
}
});
}
sock.on("message", function(data, rinfo) {
//listen for messages and print them
console.log(data);
//Check if the client's port was equal to the port to find client data on
//If so, get packet
if (rinfo.port === CLIENT_PORT) {
console.log('\nreceived');
//call function to broadcast the data out to everyone on the local network
sendMessage(data);
}
//Get the string data from the data buffer.
var stringData = data.toString(); //also could be toJSON()
console.log(stringData);
//Convert that string back into a buffer by making a new Buffer and passing it in.
//The buffer class can take a string, an array or just a number of bytes to allocate to memory
var backToBuffer = new Buffer(stringData); //can take a string, array or just a size to allocate
console.log(backToBuffer);
});
//This opens the connection and starts listening
//(Client Port, Address to listen to which is ALL, What to do)
sock.bind(CLIENT_PORT, '', function(){
sock.setBroadcast(true);
console.log('listening on port ' + PORT + "\n");
});
Client.js:
var dgram = require('dgram');
var SERVER_PORT = 22222;
var PORT = 22223;
var ADDRESS = "-";
//read input from the command line
var stdin = process.stdin;
var stdout = process.stdout;
var sock = dgram.createSocket({reuseAddr: true, type: 'udp4'});
var server_sock = dgram.createSocket({reuseAddr: true, type: 'udp4'});
function sendMessage(data) {
//onsole.log("sending data");
sock.send(data, 0, data.length, PORT, ADDRESS, function(err) {
if(err) {
throw err;
}
//nsole.log("sent");
});
}
server_sock.on("message", function(data, rinfo) {
console.log("received " + data.toString());
});
server_sock.bind(SERVER_PORT, '', function() {
console.log('listening to server port');
});
sock.bind(PORT, '', function() {
sock.setBroadcast(true);
console.log("please enter a message\n");
stdin.resume();
stdin.on("data", function(data) {
sendMessage(data);
});
});
Node.js has loads of libraries to make realtime communication chats, I don't understand the choice of using UDP and managing everything by yourself, and it also looks that you are not very expert on this. My suggestion is to use a websocket library like it can be socket.io which they even have an example of a simple chat in their website http://socket.io/get-started/chat/
Using socket.io (or similar) it will help you a lot since it has sessions so you can save the username and return it everytime you post a message.
Below I wrote a small example of the server side (took from the index.js of the get-started above).
io.on('connection', function(socket){
var username = 'RANDOM';
socket.on('chat message', function(msg){
//here you should catch messages starting with "/" and parse them to write a different message
io.emit('chat message', username + ': ' msg);
});
socket.on('update username', function(msg) {
username = msg;
io.emit('username changed', username);
});
});
I hope it helps.

Windows 2012 server not executing socket.on

I am trying to learn to use NodeJS and JavaScript to replace at least some of my Perl code.
I need to create a socket and have a server/listener accept data sent from a client.
The problem I am having is that under Windows 2012 server, the listener code below just completely ignores the socket.on command, but it works fine under CentOS.
Does anyone have any suggestions as to what I am missing?
var net = require('net');
var fs = require('fs');
var server = net.createServer(function(socket) {
console.log('At : ' + (new Date()) + '\nA client connected to server...');
console.log('IP addr : ' + socket.remoteAddress);
// Process data sent from client
socket.on('data', function(data) {
console.log('Reached socket.on function.\n');
// Following command reads the data stream from client
var string = ('IP addr : '+ socket.remoteAddress + ' sent on ' + (new Date()) + ' : ' + data.toString()+'\n');
console.log(string);
// Following command writes the data stream to a file
fs.appendFile('client-data', string, function(err) {
if (err) {
return console.log(err);
}
console.log('Data saved from client...');
});
});
// This section sends data back to client, close socket, and
// resets to accept new socket connection
socket.write('\n<svrdata>\nData received by : HS-AD02 \r\n</svrdata>');
socket.pipe(socket);
socket.end();
console.log('The client has disconnected...\n');
}).listen(10337, 'hs-ad02');
In the code above the problem has a very simple solution.
Under Windows the two lines of
socket.pipe(socket);
socket.end();
Cause the socket to close prior to the receipt of the client data.
Removing those two lines and it works just fine.

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 read TCPSocket and write to a variable

I've got a litte problem with my code snipet. I wrote a example to learn the TCP Socket Communication for a project. For the moment i can send a TCP Socket and read the answer, but i want to use the answer in other software parts. For that i tried to use the variable socketmessage but this doesn't work. Does anyone have the answer for my problem? Thanks a lot
var net = require('net');
var client = new net.Socket();
var HOST='127.0.0.1';
var PORT='20000';
var MSG="{\"REQUEST\":\"STATUS\"}";
var socketmessage;
socketmessage=getSocketMessage(MSG);
console.log ("Socket Message: " + socketmessage);
function getSocketMessage(tcpmsg){
var outData;
client.connect(PORT, HOST, function() {
console.log("Client: " + tcpmsg);
client.write(tcpmsg);
});
client.setTimeout(5000, function() { client.destroy(); });
client.on('data', function(data) {
console.log('Server: ' + data);
outData = data.toString('utf8');
console.log ("Socketmessage: " + outData);
client.destroy();
});
//Add a 'close' event handler for the client socket
client.on('close', function() {
console.log('Connection closed');
});
// Add a 'error' event handler for the client socket
client.on('error', function(error) {
console.log('Error Connection: ' + error);
});
return outData;
}
Terminal:
Socket Message: undefined
Client: {"REQUEST":"STATUS"}
Server: {"STATUS":0.000000}
This is because function getSocketMessage is asynchronous. You are trying to return the received message. The function returns immediately, outData being undefined then. Its value is
set when data arrives from server. The network I/O is evented, the event you use is data
client.on('data', function(data) {
The received message can only be handled properly inside the event-handler for data. You would have to call your other part from here itself.
You can create a read stream and once the stream ends you may process the data.
var readStream = fs.createReadStream(path of the file, 'utf8'); //you can use path.join(loc, filename)
var data = '';
readStream.on('data', function(chunk:any) {
data += chunk;
}).on('end', function() {
let gotContent = data.toString(); //
doWhatEver(gotContent) //the method is async or promose
then(function(result){
console.log(result); //desired output
})
});

Resources