Beefy Boxes and Bandwidth Generously Provided by pair Networks
Perl-Sensitive Sunglasses

Timeout problem using IO::Socket

by ChOas (Curate)
on Sep 27, 2000 at 13:35 UTC ( #34165=perlquestion: print w/replies, xml ) Need Help??
ChOas has asked for the wisdom of the Perl Monks concerning the following question:

You know you've been programming to long when your debugging lines contain swear words

I use IO::Socket to create a new socket, which connects
to a certain port on a host...
I'm not sure if this is a valid host, so, I would like
to set up an alarm handler to stop the Socket from trying
after a few seconds....

Alarm handler set up, I set my alarm for 3 secs.

my $Socket=IO::Socket::INET->new("$Host:$Port") or return(1,"Error setting up connection");

(Just to clear this up, the code in my alarm handler has
been varied from setting an Errorflag, to exiting and to
printing some VERY rude words....

My program runs ($Host= so, nonexistant)
and exits after my alarm time with "Alarm Clock" on STDERR

Just to inform you: *I* did NOT print that anywhere...

Things I tried:

    - Catching $SIG{__DIE__} : No result
    - Evalling the thing : No result
    - Fiddling with IO::Socket::timeout : No result

I'd like to put it this way: Help me please!


Replies are listed 'Best First'.
(jcwren) Re: Timeout problem using IO::Socket
by jcwren (Prior) on Sep 27, 2000 at 15:40 UTC
    You shouldn't need a timeout on the connect, but rather, on any reads (and possibly writes) to/from the socket. Here's an example of some code that I recently used that makes use of the alarm() handler.

    It does not check the result of the signal handler, but suffices to know that the signal handler fired, and broke out of the eval(), which is waiting for a response on the open socket. (In this case of the code, all I need to know is that the remote host sent something (anything), to indicate it received the packet I sent it. It's not extremely robust code, but it served my purposes for playing a .WAV file to a remote Windows-running PC).
    sub play_remote_file { my $file = shift; my $sock = new IO::Socket::INET (PeerAddr => 'jcwren', PeerPort => 10666, Proto => 'tcp', ); return unless $sock; print $sock $file, "\n"; $SIG{ALRM} = \&timed_out; eval { alarm (30); my $buf = <$sock>; alarm (0); }; close ($sock); } sub timed_out { die "GOT TIRED OF WAITING"; }

    e-mail jcwren
      Yes, I see that, but what would happen if
      you called this code with a valid,unreachable
      IP address (e.g. ?

      My problem is that my program hangs at the connect,
      and I want that forced out...
      I know IO::Socket::new times out pretty quickly when
      the remeote system's port I want to reach is closed,
      but I find it hanging when the system does not respond
      at all.


Re (tilly) 1: Timeout problem using IO::Socket
by tilly (Archbishop) on Sep 27, 2000 at 17:37 UTC
    What OS are you using?

    I think you are hitting a bug in Perl. I believe that Tom May nailed it. I think that it has been "fixed" for some definition of fixed, but judging from this the fix is probably not going to make you happy. The actual patch is here. Judging from that you need IO::Select available with a "blocking" method to do timeouts properly.

    I don't have time to pursue this further, but I think that anyone who wants to get their hands dirty with Perl is likely to find getting blocking working on your platform to be a good place to get your feet wet.

(jcwren) RE: Timeout problem using IO::Socket
by jcwren (Prior) on Sep 27, 2000 at 17:37 UTC
    Here's a version that times out on opening failures. I'm still not clear where your actual concern is, since (on my machine) opening the socket times out after 5 seconds or so, in any case. By the way, if I ping 127.0.0.x on my machines, I get a reply, and connecting to a non-existant socket returns an immediate error. I had to attempt to connect to an IP address that I *knew* didn't exist to get the timeout to occur, and set a fairly short timeout.

    The reason we (I) have to use a variable and not $@ (see perldoc -f eval), is because apparently IO::Socket sets up it's own eval() statement, and $@ never gets set. I had a version of code where the die() returned a string, and I found that although the die() was executing (determined by a print statement), $@ was not being returned correctly. Perhaps someone more enlightened than I can explain this (it's at the bottom of the node). I'm using 5.005-63 at work, and can't get to my machine at home to try it on 5.005_03.
    #!/usr/local/bin/perl -w use strict; use IO::Socket; { my $timeout = 0; my $sock = undef; $SIG{ALRM} = sub {$timeout = 1; die}; eval { alarm (2); $sock = new IO::Socket::INET (PeerAddr => '', PeerPort => 29, ); alarm (0); }; die "Can't open socket: timeout=$timeout\n" if ($timeout or !$sock) +; print "I would print to the socket now, if I knew what I was connec +ted to\n"; close ($sock); }

    #!/usr/local/bin/perl -w use strict; use IO::Socket; { my $sock = undef; $SIG{ALRM} = sub {die "GOT TIRED OF WAITING"}; eval { alarm (2); $sock = new IO::Socket::INET (PeerAddr => '', PeerPort => 29, ); alarm (0); }; die "Can't open socket: $@\n" if (!$sock); print "I would print to the socket now, if I knew what I was connec +ted to\n"; close ($sock); }

    e-mail jcwren
Re: Timeout problem using IO::Socket
by ChOas (Curate) on Sep 27, 2000 at 16:14 UTC
    Just a quick example, I want this to time out On MY conditions when no connection can be set up to the entered IP address,believe me, there were a LOT of alarms, evals, etc. in here ;))
    #!/usr/bin/perl -w use strict; use IO::Socket; die "Usage: <IP address> <Port>\n" unless (scalar @ARGV==2); my $Status="Failed"; my ($Host,$Port)=@ARGV; my $Socket=IO::Socket::INET->new("$Host:$Port"); $Status="Okay" if $Socket; die "Everything $Status\n";
Re: Timeout problem using IO::Socket
by lhoward (Vicar) on Sep 27, 2000 at 16:44 UTC
    I know this doesn't really address your problem directly, but....

    Have you considered pinging (Net::Ping) the host first to make sure it is alive before you enter the IO::Socket section of your code? It may be much easier than handling the connection timeout the way you want to.

      Net::Ping would be a problem on UNIX machines. ICMP pings require the script to be run as root. Windows users won't have the same problem.

      You could either try to patch your local version of Net::Ping to disable the root requirement, or use backticks or system to execute the ping.

Re: Timeout problem using IO::Socket
by BastardOperator (Monk) on Sep 27, 2000 at 16:53 UTC
    You know you've been programming to long when your debugging lines contain swear words

    shoot, that's just the intermediate stage, you'll have prayers in your code when you've really been programming too long :).

    i.e. "Oh lord, who art in heaven, please make this code work, aaaammmmmeeennnn"
(tye)Re: Timeout problem using IO::Socket
by tye (Sage) on Sep 27, 2000 at 17:51 UTC

    Hubris time here. I think everyone has missed the problem. If your program is printing "Alarm Clock" then you haven't set up your $SIG{ALRM} handler correctly. You didn't show us that part of the code. "Alarm Clock" is what is printed by the default handler for SIGALRM.

            - tye (but my friends call me "Tye")
Re: Timeout problem using IO::Socket
by ChOas (Curate) on Sep 27, 2000 at 18:18 UTC
    *grin*, Don't you guys love this problem ? :)))

    I just checked jcwrens option ... can anyone tell
    me this is the way to set up an alarm handler ?..
    'coz it for sure prints 'Alarm Clock' for me ;))
    montest@XXX-test$ ./test I would print to the socket now, if I knew what I was connected to montest@XXX-test$ ./test Alarm Clock montest@XXX-test$
    Any Ideas ?.. btw.. thank you all for helping me out here
    update Oh, I usually set my alarm handler this way:
      How about setting your alarm more directly, for more accurate debugging -
      $SIG{ALRM} = sub { die "DIE DIE DIE!\n" };
      Show us the actual excerpt of your code -- you're asking us to use our imaginations in dreaming up possibilities for what is obviously a subtle problem.


      Well, that looks right as far as it goes. But if your program is printing "Alarm Clock" and then dieing, then you almost certainly are not setting up your alarm handler properly. Perhaps you are doing this too late, undoing it too early, have it in some conditional that you think is being run but isn't, etc. Perhaps some other code is setting up its own alarm handler and overwriting yours. You might want to step through this with the Perl debugger.

              - tye (but my friends call me "Tye")
RE: Timeout problem using IO::Socket
by lolindrath (Scribe) on Sep 27, 2000 at 22:15 UTC
    Greetings, I was interested in the this sig handler problem so I found a simple example in my book and wrote it up. Well, it worked fine under linux but Windows doesn't seem to like the alarm function. Just wanted to note this quick compatibility problem.

Re: Timeout problem using IO::Socket
by ChOas (Curate) on Sep 28, 2000 at 11:46 UTC
    Hmmmmm maybe I should have mentioned this earlier
    I found this in
    local($SIG{ALRM}) = $timeout ? sub { undef $fh; } : $SIG{ALRM} || 'DEFAULT';
    Still... There is no reason why MY alarm handler (defined)
    was/is overwritten

    Eeehm, as for original code...: The code jcwren
    posted above gives me the same results, and it's
    pretty clear code...
    Has anyone else tried his code ?

    Oh, I'm running on a sun sparc ultra4, SunOs 5.6,
    Perl 5.004_04...

    Code from jcwren gives me the same 'Alarm Clock' on
    RH Linux 2.0.36, i386, also Perl 5.004_04
Re: Timeout problem using IO::Socket
by ChOas (Curate) on Sep 28, 2000 at 13:19 UTC

    It must be perl... code works on an IBM RS6000
    running AIX 4.3, perl version 5.005_03 .

    I should have checked every system first for
    incompatibilities before asking questions here

    I'll just have to find a way around this, or get management
    to upgrade Perl on all our platforms (can you spell 'Hell' ? :))

    I'm sorry guys, thank you all so much for your help.


Log In?

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://34165]
Approved by root
[Corion]: ... gets called once. The data structure for that is just a hash of arrays, mapping the event type to a queue of registered one-shots, and the first one-shot from the queue gets removed and called.
[Corion]: But now I want to register a one-shot for two events, of which only one will arrive, so my data structure doesn't work anymore...
[Lady_Aleena]: Corion, ouchy.
[Corion]: (maybe I should write this up as a SoPW) - currently, the "most efficient" data structure I come up with is a single array which I scan for the first fitting one-shot. Not efficient but I don't expect more than five outstanding one-shots anyway
[choroba]: can't you create a meta-key corresponding to the disjunction of the events?
[robby_dobby]: Corion: Heh. This whole thing smells of Strategy Pattern or MVC pattern.
[Corion]: And performance linear to the number of registered one-shots doesn't feel that bad. Maybe I should collect statistics on how many callbacks are outstanding ;)
[Corion]: choroba: Yes, but the longer I thought about efficient hashes mapping the event type back to their callbacks, and how to keep them in sync, the more I thought that all that optimization might just not be worth it, even if it's horribly inelegant
[Lady_Aleena]: My biggest problem with hashes at the moment is one with 2,501 keys.
[choroba]: how many event types are there?

How do I use this? | Other CB clients
Other Users?
Others perusing the Monastery: (9)
As of 2017-05-29 07:54 GMT
Find Nodes?
    Voting Booth?