avo has asked for the wisdom of the Perl Monks concerning the following question:

Hi guys, I am trying to find the fastest way to determine whether a specific port is open on a host in my network... The problem that I have is that I need this to take very little time. So far i have been using the following code:

use Socket; socket (SOC, PF_INET, SOCK_STREAM, 6) || die; my $dest = pack('S n a4 x8',2,555,$svradr); if (! connect (SOC, $dest)) {$errorcode=1;}
but it takes a lot of time... (about a second) I am on Win32 using Active State Perl.

Is there a way I can speedup this process? ... by either specifying minimal timeout or something like that that will make everything faster?
Thank you very much for your answer.
  • Comment on Fastest way to determine whether a specific port is open via a Socket
  • Download Code

Replies are listed 'Best First'.
Re: Fastest way to determine whether a specific port is open via a Socket
by Nemurenai (Acolyte) on Oct 30, 2006 at 13:24 UTC
    You probably already know this, but timeouts are there to give the socket time to answer....

    If the one second delay annoys you, I suggest that you launch a seperate thread that tests the port while your main program does whatever it does and then later parse the result.

      The program that I am writing is reading content from files that are in a folder with filename looking like this:
      IP_ADDRESS.txt. The content get's submitted to the IP_ADDRESS and the file deleted. Then the next one and so on. The important thing is that the files that didn't go through must be retried again and again, in the mean time there are newly created files, which content can not be delayed by the retry procedure. That's why I am looking for rely fast or independent process (thread) to do the retrying. Your input is highly appreciated.
        OK, so you've got a system which is doing message passing between servers based on IP, where both latency and reliability are important.

        Implementing reliability reliably (hah!) is pretty hard. How well are you covering against power failure (you're fsync'ing file descriptors, right? Are you flushing stdio buffers beforehand?) You're triggering off of the existence of files - do you have race conditions where a file is created (empty) and might be processed before it's filled in? You're processing collections of related files. Are they created in a specified order?

        I'd seriously consider using existing software for this. In particular, either find a message passing module/library of even consider good old store-and-forward SMTP. Any grown-up mail system will have the reliability thing sorted and also not have any issues about one failing delivery stalling the entire queue. You might need to tune connection timeouts and retry timeouts though.

        If you don't like this idea and want/need to write it yourself, you're either going to have to get threaded, multi-process or get asynchronous. All of these solutions will add a lot of complexity to your setup and your best chance is to pick the one you understand best.

        If it were me and I had to implement this sort of thing then I might go for an async, event-based system and a simple UDP protocol. The events are then as simple as:

        1. New file to process (add new memory record, send UDP msg)
        2. UDP ACK received (clear memory record, log delivery)
        3. Timed event: UDP response not received (inc retry counter in mem record, retry UDP send or discard+log)
        4. Timed event: poll for new files (OR use system filesystems to generate notification events)
        It shouldn't get much more complex than that, but you will be doing async programming, so you can get bitten by some things taking unexpectedly longer than you think sometimes (e.g. DNS queries).

        You'll also have to think about how much state you need to save on shutdown/restore and if you need to sync it to prevent against uncontrolled shutdown (power loss).

        If you want to do multiprocess, cpan throws up "Parallel::ForkManager" as a possibilty. That might help. The things which make multiprocess painful include sharing information after process creation time, beyond the child exit code. In your case, you might get away with a simple succeed/fail exit code for each delivery which might make things quite simple.

      I am not very familiar with threads. Can you may be show me how to do that ? I would really appreciate that. :)
        It's insanely easy actually...if the function is simple; The following should be self-explanatory...I hope.
        use warnings; #mmmm use threads; sub myfunc { print "Checking out port\n"; wait 2; return 42; } print "Starting thread\n"; $thread = threads->new(\&myfunc()); print "doing some stuff\n"; wait 4; $result = $thread->join(); print "The result is $result\n";
Re: Fastest way to determine whether a specific port is open via a Socket
by tcf03 (Deacon) on Oct 30, 2006 at 20:30 UTC
    The following should work for you
    use strict; use warnings; use IO::Socket::INET; sub connected { my $host = shift; my $tcp_port = shift; my $sock = IO::Socket::INET ->new( Timeout => 2, PeerAddr => $host, PeerPort => $tcp_port, Proto => 'tcp' ); return $sock ? 0 : 1; }
    Ted
    --
    "That which we persist in doing becomes easier, not that the task itself has become easier, but that our ability to perform it has improved."
      --Ralph Waldo Emerson