pie3636
pie3636

Reputation: 814

How to make a node.js application keep listening after closing a socket?

I'm trying to set up a node.js application that could receive connections and still be listening to port 9001 once a socket is ended. How can I do that? Here is my current code (it doesn't close after the socket.end(), but it won't accept any other connections) :

var net = require('net');
var mySocket;

var server = net.createServer(function(socket) {
    mySocket = socket;
    mySocket.on("connect", onConnect);
    mySocket.on("data", onData);
});

function onConnect() {
    console.log("Connected");
}

function onData(command) {
    if (command == "exit") {
        console.log("Exiting");
        mySocket.end();
    }
}

console.log("Waiting for incoming connections");
server.listen(9001);

I tried to add another server.listen(9001); after the socket.end();, but I get a : Error: listen EADDRINUSE message. Also, will that code be able to receive several connections coming from different addresses at the same time, and handle them separately?

This is the full code. When executed, node.js receives 4 commands from the Flash application, and works properly (except that the onConnect() function seems never to be called), and the "exit;" command closes the socket properly, yet if I reload the Flash application, it doesn't connect to the server

var net = require('net');
const PACKET_SEPARATOR = 59 // ;
var connection_ack = false;
var counter = 0;

var server = net.createServer(function(socket) {
    function onConnect() {
        console.log("Connected to Flash");
    }

    function dataHandler(command) {
        if (command[command.length - 1] != String.fromCharCode(PACKET_SEPARATOR) && connection_ack) {
       console.log("SEP : " + PACKET_SEPARATOR + " - last : " + command[command.length - 1] + " - ack " + connection_ack);
            console.log("CAUGHT EXCEPTION : WRONG PACKET FORMAT --- " + command + " --- " + command.length);
        }
        if (command == "exit;") {
            console.log("Received exit request from " + socket.address().address + ":" + socket.address().port + " (" + socket.address().family + "). Ending connection...");
            socket.end();
        }
        else if (command == "<policy-file-request/>\0") {
            socket.write('<cross-domain-policy>\n<allow-access-from domain="*" to-ports="*" />\n</cross-domain-policy>\0', 'utf8');
            console.log("Policy file sent to " + socket.address().address + ":" + socket.address().port);
            player1.pxacceleration = 0;
            player1.pyacceleration = 0;
            connection_ack = true;
        }
        else {
            console.log("Got data from " + socket.address().address + ":" + socket.address().port + " (" + socket.address().family + ")");
            console.log("--> " + command);
            counter++;
            socket.write("Received " + counter + " commands;", 'utf8');
            console.log("Sending : Received " + counter + " commands;");
        }
    }

    function onData(d) {
        var command = "";
        for (i=0; i <= d.length - 1; i++) {
            command += String.fromCharCode(d[i]);
            if (d[i] == PACKET_SEPARATOR || i == d.length - 1 && !connection_ack) {
                dataHandler(command);
                command = "";
            }
        }
    }

    socket.on("connect", onConnect);
    socket.on("data", onData);
});

console.log("Ready. Waiting for incoming connections");
server.listen(9001);
server.listen(80); //TODO : Remove?     

Upvotes: 2

Views: 2991

Answers (1)

enolam
enolam

Reputation: 221

As jfriend00 said, using mySocket as a global is not recommended. Try the below instead.

var server = net.createServer(function(socket) {
    function onData(command) {
        if (command == "exit") {
            console.log("Exiting");
            socket.end();
        }
    }
    socket.on("connect", onConnect);
    socket.on("data", onData);
});
...

This eliminates the need for the global in the first place. This should also allow multiple sockets and prevent the original error. I think. I'm new here, so I guess we will see.

EDIT Alright. I've been interacting with your code via telnet. I've also read up on some of the documentation. First, the socket.on("connect", onConnect); listener should be moved(along with the onConnect function) into the global scope and changed to server.on("connection", onConnect);. The reason for this is that the socket event listener connect is a client side listener. We are working server side. The server side listener for new connections is connection and the server should be listening for it in the same way it is listening for connections on a particular port.

This part of your code should look like this now:

//more code up above here
....
    function onData(d) {
        var command = "";
        for (i=0; i <= d.length - 1; i++) {
            command += String.fromCharCode(d[i]);
            if (d[i] == PACKET_SEPARATOR || i == d.length - 1 && !connection_ack) {    
                dataHandler(command);
                command = "";
            }
        }
    }
    socket.on("data", onData);
});

function onConnect() {
    console.log("Connected to Flash");
}

server.on("connection", onConnect);
....
//more code below here

However, the code would not recognize exit as a command via telnet. I was unable to figure this bit out. Since your question did not cover this problem it might just be me or you have it figured out.

EDIT 2 The code below keeps it local.

var server = net.createServer(function(socket) {

    function onConnect() {
        console.log("Connected to Flash");
        socket.write("we're connected");
    }
....
    function onData(d) {
        var command = "";
        for (i=0; i <= d.length - 1; i++) {
            command += String.fromCharCode(d[i]);
            if (d[i] == PACKET_SEPARATOR || i == d.length - 1 && !connection_ack) {    
                dataHandler(command);
                command = "";
            }
        }
    }
    onConnect();
    socket.on("data", onData);
});

Upvotes: 1

Related Questions