in reply to Using IO::Socket

I believe I solved my problem with the following code. It seems to be working well with testing. See any issues?

#!/usr/bin/perl use IO::Socket::INET; use IO::Select; $timeout = 180; $host = shift; $port = shift; $string = shift; my $TIMEDOUT, $counter; $MySocket = new IO::Socket::INET->new("$host:$port") or die "connect: +$@"; $command = "EDMSFT\|$string\|\@\n"; $MySocket->send($command); while (($text !~ m/$string/)&&(!$TIMEDOUT)&&($counter<30)) { if( () = IO::Select->new($MySocket)->can_read($timeout) ) { my $sender = $MySocket->recv( $text, 1024, 0 ); $counter++; ### TIMEOUT if counter hits 30 without a match } else { $TIMEDOUT=1; } } if ((!$TIMEDOUT)&&($counter<30)) { print "GOOD\n"; } else { print "TIMEDOUT\n"; } close $MySocket; exit;

Replies are listed 'Best First'.
Re^2: Using IO::Socket
by thospel (Hermit) on Oct 12, 2004 at 16:32 UTC
    Pretty good in fact, but it has a few flaws:
    • A connect can take a long time too
    • Writes can block too
    • The read can be satisfied in several chunks
    • Operations can be interrupted

    Here is a (only sligtly tested) version of how I would do it when using IO::Socket::INET and IO::Select (in reality I would use POE). Like you I will assume the protocol does pipelining, otherwise you should immediately start checking for readability to drain pending output that can block the server. I'm also assuming that the server finishes with EOF, otherwise you might already want to start checking for your target string inside the read loop.

    #! /usr/bin/perl -w use strict; use IO::Socket::INET; use IO::Select; use POSIX qw(EWOULDBLOCK EINTR); my $timeout = 180; my ($host, $port, $string) = @ARGV; my $too_late = time()+$timeout; my $socket = IO::Socket::INET->new(PeerAddr => "$host:$port", Blocking => 0) || die "Could not connect to $host:$port: $!\n"; # Write (also handles connect, since being connected is a writability +event) $SIG{PIPE} = "IGNORE"; my $command = "EDMSFT|$string|\@\n"; my $select = IO::Select->new($socket); while ($command ne "") { my $left = $too_late - time(); if ($left <= 0) { print "TIMEDOUT\n"; exit; } next unless $select->can_write($left); if (defined(my $rc = syswrite($socket, $command))) { substr($command, 0, $rc, ""); } else { next if $! == EWOULDBLOCK || $! == EINTR; die "Error writing to $host:$port: $!\n"; } } # Read my $text = ""; while (1) { my $left = $too_late - time(); if ($left <= 0) { print "TIMEDOUT\n"; exit; } next unless $select->can_read($left); my $rc = sysread($socket, $text, 4096, length $text); if (!$rc) { last if defined $rc; # EOF next if $! == EWOULDBLOCK || $! == EINTR; die "Error reading from $host:$port: $!\n"; } } $text =~ /\Q$string\E/ || die "Unexpected answer from $host:$port: $text"; print "GOOD\n";
      Thanks much. I'll implement what I can use and see how it goes. Really appreciate the input. The server should never send an EOF. It's a continuous stream of data. The query string was added because when the app is broken, it either outputs nothing or outputs one short heartbeat every 30 secs or so (that doesn't contain the query string).