1

I have a Server socket and a device which uses TCP long-connection mode.
They can connect and exchange data together. The node.js server is something like this:

net.createServer(function (socket) {
   console.log('ip:port' + socket.remoteAddress +':'+ socket.remotePort);
   socket.on('data', console.log);
}).listen(‘0.0.0.0’, 8888);

The device connects just right and I'm able to receive data from it. I can send commands to it by using the same process, by just doing socket.write('dothisplease') and this works too.

Now I have another worker process which should be sending commands at regular intervals. I can get ip and port from console.log when the device connects, it looks like: xx.xxx.xx.xxx:63024
I tried using this combination ip:port to create new connection:

var client = new net.Socket();
client.connect(device_port, device_ip, function () {
  client.write('dothisplease');
});

... but the result was ECONNREFUSED

  1. Is it right to use the same port to create a second connection to the device?
  2. Why does it work from the same process, but does not work from another?
  3. Eventually, can I pass the socket to another node Worker process. How?

Thanks a lot!

Silvia Tacher
  • 109
  • 1
  • 2
  • 11
  • You cant use remotePort to make another connection, you should have a listening service on the device to start a connection or reuse the same socket as far as I know – KeySee Oct 17 '22 at 22:41

2 Answers2

1

Your server is listening on port 8888. That's the port that all clients need to connect to. The client will also have to know what the server's IP address is in order to connect to it. A client uses a target IP address and target port to specify the destination for a TCP connection.

socket.remotePort is not the port that anyone can connect on. That is the outgoing port that the first client used to connect to your server port. The outgoing port is a client bookkeeping thing that helps the client keep track of which network traffic belongs to which socket and is usually randomly assigned by the client.

You read more about what remotePort is here.

For reference, a TCP connection consists of two endpoints and each endpoint has an IP address and a port. The server will need to have a known IP address and a known port that all clients will use in order to connect to it. The client will already have its own IP address. Then, during the process of making a TCP connection to a server, the client will dynamically allocate an unused port number for the communication for this socket. That port number is used by the client to keep track of which network traffic belongs to which socket. This is not a port number that anyone can connect to.

Is it right to use the same port to create a second connection to the device?

No. You can't create a connection to a client. You can only create a connection to a listening server. And, you couldn't use the client's port that belongs to that other socket either.

jfriend00
  • 683,504
  • 96
  • 985
  • 979
  • Yeah, that was one of my fears. Basically I should create another server on the device to accept new connections or reuse the same connection. Right? Is it possibile to pass the a socket a connection to another process? In this case its from node:worker_threads – Silvia Tacher Oct 17 '22 at 22:29
  • 1
    @SilviaTacher - There is some ability to pass a socket connection to another process. But we'd need to know a lot more about what you're doing to know whether that's a feasible solution for your particular issue or not. It might make more sense for the other process to just send a message to the server that already has the connection and ask it to send some data over the existing connection that it already has to the client. – jfriend00 Oct 17 '22 at 22:31
  • Basically I need to make two separate services to manage the dataflow. The main process will elaborate the requests and save the output, which is pretty slow and that's where the devices connect. So to make it more performant I was trying to move the sending part to another process via worker_threads... – Silvia Tacher Oct 17 '22 at 22:38
  • 1
    @SilviaTacher - Sending packets of data over a TCP socket is not CPU intensive. It just makes an OS call and hands the data off to the OS to manage the networking. You should use a workerThread for CPU intensive stuff, but not for networking which is all asynchronous and very efficient for nodejs. – jfriend00 Oct 17 '22 at 22:56
0

Solution:

// .... Rest Of Code ... //

// session management object / array
const clients = [];

// TCP server for receiving data from clients
const server = net.createServer(handleClientConnection);

function handleClientConnection(socket) {
  // .... Rest Of Code ... //
  console.log('con: ' + sock.remoteAddress + ':' + sock.remotePort);

  // Manage the client session after receive the client data as we can retreive client_id from the data
  // take this as data sent from client (device) FC11236772129
  // and deviceid / client_id start from index 2 - 5 thus client_id = 1123
  sock.on('data', function(data) {
    const buffer = data.toString().trim();
    const clientId = buffer.slice(2, 5); //extract client_id from data received
    const sessionId = socket; //store socket as sessionId as it contain remoteAdrress and Port for the respective client 

    // Store client session
    /* When dealing with a large number of clients, 
    storing sessions in a JavaScript object 
    may not be the most efficient approach
    due to potential performance and memory limitations. 
    In a production environment with a high number of clients, 
    it's recommended to use a dedicated session management solution
    that is optimized for scalability and performance */
    clients.push({
      clientId,
      sessionId
    }); // add a client to the clients array
    // One popular option is to use a distributed key-value store or a caching system, Eg. Redis


    console.log('receive ' + sock.remoteAddress + ': ' + buffer);

  });

  // Simulating application-level processing delay (replace this with actual processing)
  setTimeout(() => {
    const cmdrply = 'Command';
    // get clientid from you data store (database or ..) as 
    // your project requirement
    // in our case
    const clientSocket = getSessionIdByDeviceId("1123");
    if (clientSocket !== null) {
      sendReplyToClient(clientSocket, cmdrply);
    }

  }, 2000); // Simulating 2 seconds delay for processing


  // .... Rest Of Code ... //
}

function sendReplyToClient(clientSocket, rply) {
  clientSocket.write(rply);
}

function getClientByDeviceId(deviceId) {
  return clients.find(client => client.deviceId === deviceId);
}

function getSessionIdByDeviceId(deviceId) {
  const client = getClientByDeviceId(deviceId);
  return client ? client.sessionId : null;
}

// .... Rest Of Code ... //
Tyler2P
  • 2,324
  • 26
  • 22
  • 31