Beefy Boxes and Bandwidth Generously Provided by pair Networks
We don't bite newbies here... much
 
PerlMonks  

What's the best way to find an unused TCP port on the local system

by DrWhy (Chaplain)
on Oct 20, 2006 at 17:33 UTC ( #579649=perlquestion: print w/ replies, xml ) Need Help??
DrWhy has asked for the wisdom of the Perl Monks concerning the following question:

Greetings Brothers (of any gender),

I have an app that starts up a server that binds to a TCP port. It has a default port number, but can bind to any port. There is a high probability that at some point, more than one of these servers will be running on the same system at the same time. I want to make sure that second and subsequent servers don't die on startup just because they picked a port that another server is already using.

What would be the best way to determine what ports are available on the local system? I could use Net::Netstat::Wrapper, I believe, but I'd like to avoid depending on an external app (netstat), if possible.

--DrWhy

"If God had meant for us to think for ourselves he would have given us brains. Oh, wait..."

Comment on What's the best way to find an unused TCP port on the local system
Re: What's the best way to find an unused TCP port on the local system
by samtregar (Abbot) on Oct 20, 2006 at 17:37 UTC
    I think you'll end up with a race-condition if you try to look at all open ports and then pick one. Instead, why not start at a fixed base and work your way up till you find an open one? Just keep $port++ till you find one that's free.

    -sam

      Yeah, I'm willing to live with a small race condition here. This is an internal tool and the frequency with which the tool is used means that the frequency at which two servers would run at the same time is very low, and thus the probability of the race condition become a concern is extremely low indeed.

      Since this server is actually a c++ app and I have to communicate the port number by writing a new configuration file each time I don't want to muck with catching a failed startup, determine if it's because the port was in use, write a new config file and try again.

      --DrWhy

      "If God had meant for us to think for ourselves he would have given us brains. Oh, wait..."

Re: What's the best way to find an unused TCP port on the local system
by ikegami (Pope) on Oct 20, 2006 at 17:39 UTC

    If using socket

    Bind to port zero. The system will pick an unused port. You can find out the number of the port to which the socket was bound as follows:

    use Socket qw( sockaddr_in ); my $port = (sockaddr_in(getsockname(SOCK)))[0]; print("Listening to port $port.\n");

    If using IO::Socket/IO::Socket::INET

    Don't specify a LocalPort or use LocalPort => 0. The system will pick an unused port. You can find out the number of the port to which the socket was bound as follows:

    my $port = $sock->sockport(); print("Listening to port $port.\n");

    Update: Added IO::Socket method.

      I have one more question. I'm interested in this problem of finding an unused port on a local system too. It's for some client/server based IPC. Given any method of those mentioned here (I prefer yours most), how would I go to communicate it to possible clients? One way could be to write that info into a (configuration) file, as the OP suggests. But that is somewhat unsatisfactory because if I wanted to make the processes communicate through files I may have chosen to do by means e.g. of a named pipe in the first place.

      Of course I may set up a predefined port, and failing that, use a workaround. On the client side, if the server doesn't respond, and only then, the client itself may check a suitable file. However how do people generally deal with this problem? (If it is a problem at all...)

        It's hard to answer without knowing what you are doing. What's the difference between the server on port A and the one on port B? Or rather, why would someone want to connect to the server on port A as opposed to one on port B?

        Generically speaking, the problem is the same as finding a someone's phone number. How do you that? Maybe you search a directory. Maybe you ask someone who knows. In both of these, you query an external system.

        Therefore, a possible solution is to have the server communicate it's vitals to a directory server. The client (user or program) then selects the server to which it wishes to connect from the directory.

        For example, ICQ used to work this way (before changes were made to fight spam and privacy invasion). The ICQ client would become a server and then connect to the central ICQ server. Someone wishing to send you a message would query the central ICQ server for your IP address.

        Another example is battle.net. People wishing to play Starcraft over the internet log into the battle.net chat server (through the game). When someone creates (hosts) a game, Starcraft contacts battle.net letting it know at which IP the game resides. battle.net would present a list of running games to users and passes on the IP address and port to people wanting to join.

        Update: Added examples.

        portmap is the traditional UNIX RPC way of doing this. It has just one service on a well-known port, which allows you to ask for a service by name and get the port it's currently running on.

        It may be overkill for your application, but maybe implementing something simpler with a SOAP interface would work.

      That's a good trick to know, but it won't work for me, since the server I'm starting is written in C++. My Perl code is an external controller for the server and will also act as a client. (UPDATE: FYI it's a test script)

      --DrWhy

      "If God had meant for us to think for ourselves he would have given us brains. Oh, wait..."

        This is not a Perl "trick". It's a feature of the system's socket library. You can use port 0 in C++ as well.
      Hmm... if I just want to know which next port (starting from e.g. 1025) is free, but without binding to it (e.g. to pass the port number to an external program) - how can that be done? I'm doing an (unportable) system "lsof -i :$port" in ssh chain to check whether it's busy. Is there a better (portable) way?

      cheers,

      --shmem

      _($_=" "x(1<<5)."?\n".q·/)Oo.  G°\        /
                                    /\_¯/(q    /
      ----------------------------  \__(m.====·.(_("always off the crowd"))."·
      ");sub _{s./.($e="'Itrs `mnsgdq Gdbj O`qkdq")=~y/"-y/#-z/;$e.e && print}
        No, it's not possible. Such a feature would unavoidably introduce a race condition. Your child process needs to either communicate the port back to you, or must inherit the opened socket from you.

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://579649]
Approved by ww
Front-paged by ikegami
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others meditating upon the Monastery: (5)
As of 2014-08-29 04:07 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    The best computer themed movie is:











    Results (275 votes), past polls