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

I am using the following script

$sock = new IO::Socket::INET ( PeerAddr => $$display{'dp_ipaddress' +}, PeerPort => $$display{'dp_tcpport'}, Proto => 'tcp', Blocking => 1, Timeout => 3, ); # blah blah constructing $msg $sock->send($msg); $resp = <$sock>;

My problem....

The script is getting stuck at '$resp = <$sock>;'

My application, I am sending a message to an electronic display with a microcontroller, which should respond with an ACK (0x6), a NACK (0x15) or no response at all if the display is dead or cable is broken.

I use the response to update a database to indicate to user which displays are working. I have to iterate through many displays and I don't want to get stock at the first non-responding one.

Any ideas on how to get past this problem. I have tried the various eval...die suggestions and select options but none works. I am developing on Windows but product will be deployed on Linux.

Replies are listed 'Best First'.
Re: Getting stuck reading from a socket
by zentara (Cardinal) on Jul 11, 2012 at 14:32 UTC
    The script is getting stuck at '$resp = <$sock>;'

    Yeah, that's a common problem with sockets. You usually use IO::Select to read sockets reliably, but if you want to go simple, try either of these:

    my $msg; $sock->recv($msg, 1024); # or sysread ( $sock, my $line, 1024);

    I'm not really a human, but I play one on earth.
    Old Perl Programmer Haiku ................... flash japh

      Thank you very much

      This works

      Oops! I spoke too soon. It doesn't work if the hardware does not respond.
        If the hardware dosn't respond, there is no program in the world that will read anything out of that socket. You need to explain/explore the communication protocol of the hardware device, and find out what it needs to trigger a response. All I can do is make guesses in the dark.

        It might be as simple as adding a newline to your send:

        $sock->send( "$msg\n" ); # possibly " $msg\r\n " # or send a blank line $sock->send( "\n" );
        to tell the hardware you are done sending your line.

        You might also try something like this hack to inefficiently read 1 byte at a time

        while(my $len = sysread( $sock, my $buffer, 1) > 0) { print "$buffer\ +n"; }
        Otherwise, you need to provide much more information about your hardware. Does the hardware have a driver written in c or c++? Can you look at the driver's source code to see what it does? Does the hardware have any driver that works?

        Finally, when you use the socket methods send and recv, you are establishing a 1 way-at-a-time protocol. The hardware device might be getting locked into recv mode.

        You might be better off using IO::Select on the socket and using syswrite and sysread instead of send and recv.

        A simple IO::Select program might look like this:

        #!/usr/bin/perl use warnings; use strict; my $sock = new IO::Socket::INET( PeerAddr => $host, PeerPort => $port, Proto => 'tcp', Reuse => 1 ); $sock->autoflush(1); # latest Sockets has this on by default print $sock "log in information"; my $read_set = new IO::Select($sock); my $incoming_data = ""; while (1) { my @ready = $read_set->can_read(.5); foreach my $rh (@ready) { sysread ( $rh, my $line, 1024); $incoming_data .= $line; print "$incoming_data\n"; } }

        I'm not really a human, but I play one on earth.
        Old Perl Programmer Haiku ................... flash japh
Re: Getting stuck reading from a socket
by jethro (Monsignor) on Jul 11, 2012 at 13:25 UTC

    Where is the code where you check for success of your calls? Does the new succeed? Does send succeed?

    Did you check whether the PeerAddr and PeerPort parameters to new are what you want?

    PS: I might be misinterpreting your question. Do you ask because your script always blocks on reading or because it normally works but you want to avoid blocking in case the hardware doesn't answer?

Re: Getting stuck reading from a socket
by punungwe (Initiate) on Jul 17, 2012 at 09:44 UTC
    I finally got it to work with the code structure
    use IO::Socket; use IO::Select; $sock = new IO::Socket::INET ( PeerAddr => $$display{'dp_ipaddress'}, PeerPort => $$display{'dp_tcpport'}, Proto => 'tcp', Blocking => 0, Timeout => 10, ); my $sel = IO::Select->new($sock) or die "IO::Select error $!"; if ($sel->can_write(10)) { $sock->autoflush(1); . $msg = $msg . CheckSum($msg); $sock->send($msg); my $resp; if ($sel->can_read(10)) { $sock->recv($resp, 1024); } } else { print "Error: $@: $!\n"; } . .