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

Hi folks, I am having trouble with the following script. Basically it connects to two different devices. The 'lightspace' device is a program, which sends short messages that are basically XML, I extract some values from that message, do some math on them, then I send them to another device called the 'phabrix' which then acts on that data.

The phabrix device closes the socket after each message/ack, whereas the lightspace device is happy to leave it open.

The script seems to work fine most of the time, but if a message comes in while the script is still sending messages to the phabrix device (in while loop in the main body you can see it calls the device 3 times), the script frequently hangs (it also occasionally hangs even if it has not recieved a message from the lightspace device before it's ready) It usually hangs between the first and the third message being sent to the phabrix device (shown below) It never hangs inside the phabrix subroutine.

I'm relatively new to perl, so I'm sure I've just got some bad form here, but any help you could provide would be appreciated. Also, sorry for posting so much code, not sure what might be relevant

#!/usr/bin/perl #LSPhabrix.pl use strict; use warnings; use IO::Socket::INET; use POSIX; use Term::ReadKey; my $data = 0; my $InputRed = 0; my $InputGreen = 0; my $InputBlue = 0; my $scaling = 0; my $KeyScale = 0; # flush after every write #$| = 1; # there are no newlines, so use last tag as delimiter IO::Handle->input_record_separator('</calibration>'); my ($Lssocket,$LSclient_socket); my ($Pxsocket,$Pxclient_socket); # user input and other minutia here # Connect to Lightspace and listen print "Connecting to Lightspace... "; $Lssocket = new IO::Socket::INET ( PeerHost => '127.0.0.1', PeerPort => '20002', Proto => 'tcp', Blocking => 0, ) or die "ERROR connecting to Lightspace : $!\n"; print "Connected to Lightspace.\n"; while ($data = <$Lssocket>) { #print "Received from Server : $data\n"; $InputRed = index $data, "red=\""; $InputGreen = index $data, "green=\""; $InputBlue = index $data, "blue=\""; if ($InputRed == -1) { print "msg from server ng - no color data found\n"; last; } #take the indexes and adjust to get the whole number # ------------ doing some math here that we don't need to worry ab +out ------- # and send them out phabrix ("4700", $InputRed); # *********** USUALLY HANGS HERE phabrix ("4800", $InputGreen); # ************ OR HERE phabrix ("4900", $InputBlue); print "\n"; } $Lssocket->close(); # phabrix subroutine sub phabrix { # call using phabrix( command , value ) # Where: # command is a string of 4 hex digits ie "0500" # value is an unsigned int # Remember for command that hex is in intel little endian small by +te first # Also, because phabrix doesn't always respond or ack, we will do +the # operation up to 3 times before giving up and erroring out. print "\n*"; my $Pxsocket = 0; $Pxsocket = new IO::Socket::INET ( PeerHost => '192.168.200.5', PeerPort => '2100', Proto => 'tcp', ) or die "ERROR connecting to Phabrix : $!\n"; my $magicNumber = pack "H8", "12cb5aa5"; my $commandType = pack ("H4", "0500"); my $command = shift; my $spacer = pack ("H16", "0000000000000000"); my $value = shift; my $phabrix_ACK = pack ("H12", "12cb5aa50000"); my $response = 0; my $errCount = 0; # pack command and value $command = pack ("H4", $command); $value = pack ("L", $value); while (1) { # send command $Pxsocket->send($magicNumber); $Pxsocket->send($commandType); $Pxsocket->send($command); $Pxsocket->send($spacer); $Pxsocket->send($value); print "sent "; print (unpack ("H*",$magicNumber)); print (unpack ("H*",$commandType)); print (unpack ("H*",$command)); print (unpack ("H*",$spacer)); print (unpack ("H*",$value)); print " - "; #get response $Pxsocket->recv($response,6); print " recv "; print (unpack ("H*", $response)); print ""; if ($response eq $phabrix_ACK) { print " ACK($errCount)"; last; } elsif ($errCount == 3) { #die "ERROR Too many retries to Phabrix. Exiting!\n"; $Pxsocket->close(); print "NO Ack, skipping"; last; } else { $Pxsocket->close(); $errCount = $errCount + 1; sleep (1); } } }

Thanks for your time in looking at this.

Replies are listed 'Best First'.
Re: socket problem? script hangs occasionally...
by SuicideJunkie (Vicar) on May 03, 2013 at 13:41 UTC

    It would be a good idea to do your print immediately before the send it is explaining; that way it acts as a trace. Wrapping the print/send pair up in a sub will also help you avoid repeating yourself too much. And more prints everywhere for tracing wouldn't hurt either.
    printf ("%s\n", 'stuff') if DEBUG_LEVEL > 0 is handy since you can turn it off with one constant and have it still there in case things go wrong later.

    I don't see where you test to ensure the socket is writable before you attempt to send, and readable before you read.

    I would also suggest packing up the whole message into a string before doing a single send. Fewer places for things to go wrong that way.

    Lastly, does the phabrix device perhaps expect a line terminator that you are not providing? If so, it would sit and wait; your buffers would fill up and your reads & writes would start blocking.

      Thanks, tried concatenating the send before sending the command to the phabrix... but it isn't helping. Despite peppering the code with print statements, it definitely never hangs while inside the subroutine, so the Phabrix doesn't seem to be the issue. rather it seems to hang if it receives another message from the lightspace device before it's done sending the commands to the phabrix... somehow recieving another message too early makes it stop executing once the phabrix subroutine is finished.

      To answer your question about the phabrix though, it does not require any sort of line ending. As soon as it recieves a 20 byte message, it responds ACK or NAK or sometimes not at all, and closes the socket.

      It must have to do with the way I'm reading from the lightspace.

      -ben