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

Hi, Monks. I've been exploring the world of net communications with Perl and Network Programming with Perl by Lincoln Stein. To make a long story short, I was playing around with the code in Fig. 5.6 which sets up what he calls a "gab" client and was wondering why the following alteration to the code makes the program hang:
LOOP: while (1) { { # localize change to $/ last LOOP unless @from_server = <$socket>; #<---program hangs on t +his line } print @from_server,"\n";
I naively thought that @from_server array would suck up the entire multiline output from the server, like what happens when the angle brackets are used in a list context on a regular file. Why doesn't it work with a socket?

$PM = "Perl Monk's";
$MCF = "Most Clueless Friar Abbot Bishop";
$nysus = $PM . $MCF;
Click here if you love Perl Monks

Replies are listed 'Best First'.
Re: Getting multiline input from a server
by HyperZonk (Friar) on Jul 26, 2001 at 07:48 UTC
    If I'm not mistaken, it's because of your loop structure. Say that @from_server does indeed suck up all of the data from the socket (I am not convinced that it does, the suggested idiom is to loop across while defined($input = <$socket>)), then you get the number of lines slurped back as the scalar value of the assignment. It then loops and attempts to read from the socket again. Presumably, there is no more data on the socket, so it sits there and waits for data.

    If assigning socket IO to an array works, and I would recommend using the suggested idiom instead, but if, you would want:
    @from_server=<$socket>; print @from_server, "\n";
    Note that there is no loop.

    Update: As tilly noted, I am sure that it is your loop structure; what I'm not sure of is if it is hanging on the first pass because "you can't do that with sockets" or if it is because, "you can do that," but it is hanging on the second pass through the loop.

    -HZ
      Well I can yank that loop right out of there and I still get the same behavior. I found something interesting, however. I simplified the code to this:
      my (@from_server,$from_user); while (my $from_user = <>) { # a simple "GET" command print $socket $from_user; my @from_server = <$socket>; print @from_server; } close $socket;
      Now, this code works when connected to an HTTP port. This is what had me confused. I'm discovering the the bad behavior only occurs when connected to an FTP port where it will hang. Now is this because the connection is terminated by the server in an HTTP connection? I'm guessing this is what must be happening but I don't know for sure. When connected to an FTP, it waits and waits for more data to fill the array because the connection is still open, I'm also assuming.

      $PM = "Perl Monk's";
      $MCF = "Most Clueless Friar Abbot Bishop";
      $nysus = $PM . $MCF;
      Click here if you love Perl Monks

Re: Getting multiline input from a server
by tadman (Prior) on Jul 26, 2001 at 08:16 UTC
    Localizing $/ may be the source of your problems. If the server doesn't "hang up" the connection, your program may be caught waiting for more data. Unlike a regular file, a socket doesn't hit EOF until the other end hangs up, such as using either close or shutdown.

    You could try reading a certain number of lines, or perhaps you are supposed to be watching out for a signal. Maybe it's something like this:
    my $buffer; while (my $line = $socket->getline()) { # Maybe this is the "END" line, and if it is, # bail out of the loop because we're done! last if ($line =~ /^END$/); # Otherwise, just tack that stuff onto the buffer. $buffer .= $line; } print "Read: ", $buffer, "\n";
    You could very well use <$socket> in place of the IO::Handle getline call. Note that this version will only block until the "END" line is received. The server doesn't have to hang up, and so the connection can remain open for other transmissions.

    Footnote:
    I honestly shudder every time I see those outrageous loop labels. Maybe they are promoted by shell-shocked veteran Fortran programmers, because over 99% of the time they serve no practical purpose, this single loop being a fine example. If you absolutely need them, by all means, but putting them in there "just because" is nonsense.
Re: Getting multiline input from a server
by mattr (Curate) on Jul 26, 2001 at 18:50 UTC
    I wouldn't depend on an FTP server to be nice about connections.. my guess is that you are getting caught waiting for a connection to close. Maybe it will when the other server times out..

    Net::FTP is pretty complex but it seems to use sysread (FTP::A/I and sub get in FTP.pm) although it also has many cases to deal with wierd servers and "braindead" firewalls, etc. For example I often see my linux laptop act wierdly when I try to connect to it from a Win98 machine through FTP; it will seem to hang for a long time unless I hit return and maybe still requires me to disconnect and try again (eek). Caveat I am not amazingly experienced at this but it would seem that your control loop depends on well-behaved data streams.