http://www.perlmonks.org?node_id=913549

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

Greetings Bros. I have written the following socket client to communicate with a parser running on another machine on my LAN:
#!/usr/bin/perl -w use strict; use IO::Socket::INET; $| = 1; my $socket = new IO::Socket::INET ( PeerHost => '192.168.1.107', PeerPort => '27109', Proto => 'tcp' ) or die "No socket: $!\n"; my $sent = 'This is a test.'; print $socket "$sent\n\n"; while(<$socket>) { print "$_"; } $socket->close();
It works in the sense that it sends the sentence to the parser and prints the parser's response correctly; however, after the parser output is complete the script doesn't terminate. I guess it's caught in the while loop, though it doesn't seem to be printing blank lines or anything.

I have tried changing the while loop to

my $line; while( defined($line=<$socket>)) { print $line; }
but I get the same behavior. What am I doing wrong?

Thanks,

Steve

Replies are listed 'Best First'.
Re: Why won't this socket client terminate?
by BrowserUk (Patriarch) on Jul 09, 2011 at 21:34 UTC

    Your while loop will not terminate until the server either closes the connection or uses shutdown upon it.

    Until the server takes one of these two actions, the client will block on the readline waiting for another transmission. If no transmission is forthcoming and the server fails to terminate the connection, the client will block forever.

    On the basis of what you've posted, the problem would appear to lie at the server end of the connection.


    Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
    "Science is about questioning the status quo. Questioning authority".
    In the absence of evidence, opinion is indistinguishable from prejudice.
Re: Why won't this socket client terminate?
by Marshall (Canon) on Jul 10, 2011 at 07:48 UTC
    I don't know for sure that you are writing both ends but it sounds like that is a possibility (otherwise there would have been an interface spec for the thing that you are talking to).

    1). I guess the first question is whether this is a multi-request server or not? Apparently the answer to that is: yes. It is presumably leaving the socket open for you to send additional lines to it. A single request server would have "hung up" on you when the output was finished and your while loop would have terminated.

    2). The next question is whether a result can contain multiple lines or not? If not, then you send one line via print and get one line back like: $x=<$socket>;. If the server can return multiple lines, then it has to be worked out how the client will know that all the lines have been received. One common scheme would be that the last line contains just a period '.' followed by \n. Other schemes are possible, instead of say the character '.', it could be a CTL-A or whatever you want, even a string like "END-OF-TRANSMISSION". You use a while loop to receive the incoming lines, perhaps like: while (defined($line=<$socket>) and $line !~ /^\.$/){...}

    3). The third thing to figure out is how to "hang up" from the client end. The server typically has a timer running and will "hang up" if it hasn't heard from the client for X amount of time. But to free resources more efficiently, there would be some kind of "quit" command or "quit packet". What this line would look like is up to you or was up to the server author. It can be anything that cannot be confused with a normal server request. Normally you would send this before your client exits. When the server gets this, it knows that you (the client) are going away and the server closes the socket at its end. The server doesn't get otherwise notified that you closed the socket. To be "polite" you should tell it that you are doing so, rather than rely upon it to figure this out at some later point in time.

    There are of course other considerations like signals, but these are error handling situations instead of the main line "good machine" case.

    Oh, your line: $| = 1;, doesn't do anything in your program. That statement only applies to the currently selected file handle (what print goes to by default), which in this case is stdout. I would call the autoflush() method on the $socket if you need to do this, but apparently this is not needed here.

      Actually, no someone else wrote the server. Supposedly sending a blank line will terminate the parser, which is why I terminated the call with \n\n. I will have to dig into the server code and figure out what's going on now that I know I haven't don't anything wrong on the client. And duh, yes I should use autoflush!
        Ok, sorry for being long winded. Your code looks fine although sounds like autoflush() should be used. When the server closes the socket, it will look like an EOF at your end.

        Some ideas to try that might help some not so good code at the server end: -try putting the "\n" in a separate print statement to make sure it gets sent as the first char in a packet. -try " \n" a space before \n in case this guy's regex is wrong. Other than that, I can't think of anything else you could do.

        Update: Another idea occurred to me. If you change: print "$_"; to print "****$_****"; You might see some invisible white space character in what is being returned to you (maybe the server is sending a blank line to you..and has botched the close($socket) code at their end? This is just odd because you are so very close - getting connected and a legible response back is usually way more than half the battle!

Re: Why won't this socket client terminate?
by Khen1950fx (Canon) on Jul 10, 2011 at 05:43 UTC
    I tried your script. The while loop just wouldn't work, so I abandoned it and tried it like this.
    #!/usr/bin/perl -sl use strict; use warnings; use IO::Socket::INET; my $socket = IO::Socket::INET->new( PeerAddr => '192.168.1.1', PeerPort => 'http(27109)', Proto => 'tcp', ); $socket->accept(); if($socket->connected) { print "This is a test"; } else { print "Sorry! This is not what you wanted\n"; } $socket->close(); sleep 3; unless($socket->connected) { print "This test has closed"; }