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

In the following snippet of code I am accepting a connection over $socket, which was created using IO::Socket::INET->new.

The problem that I am having with it is that it will not leave the while loop until the client terminates the connection.
($client) = $socket->accept(); my $read = ""; my $buffer; print "DEBUG Point: 1\n"; while (read($client,$buffer,1024) > 0) { print "DEBUG Point: 2\n"; $read .= $buffer; } print "DEBUG Point: 3\n"; print "$data \n";
The output from the above code is:
DEBUG Point: 1 DEBUG Point: 2
At this point it just sits and waits. Doesn't continue looping endlessly. If i terminate the connection from the client's end if then spits out the following:
DEBUG Point: 3 Test Data
If i send enough data through that it needs to loop several times to read it all, it will print the "DEBUG Point: 2" a couple times (as one would expect) and then just sits and wait until the client terminates the connection.

Any ideas what I might be doing wrong? Suggestions to fix it?

What's throwing me off is that it is not looping endlessly in the while statement, it seems to just sit at the read and wait.

Replies are listed 'Best First'.
Re: Sockets + Read
by dave_the_m (Monsignor) on Aug 17, 2005 at 23:33 UTC
    This is exactly what read() on a socket is supposed to do; wait until there's some data recieved, then return it. When the client closes the connection, indicate EOF.

    In what way do you want read() to return 0 earlier? If you want it do do that the first time there's no data available, then you need to set the socket to non-blocking. Note that in that case you'll need some extra logic to determine when and how you have read enough data, and you'll need to add a select() call to wait for motre data.

    Dave.

      I have no real way to determine when the data is finished being read, other than there is nothing else coming in. Basically, I want to read the data from the client, act on it and return the results to the client and then have the server terminate the connection. (Using sysread in this example, because according to "Network Programming with Perl, page 359" it is the safest option with a nonblocking socket)

      I've modified the code in the following way:
      ($client, my $client_addr) = $server->accept( ); my $result = fcntl($client, F_SETFL, O_NONBLOCK); my $read = ""; my $buffer; print "DEBUG Point: 1\n"; while (sysread($client,$buffer,1024)) { print "DEBUG Point: 2\n"; $read .= $buffer; } print "DEBUG Point: 3\n"; print "$read\n";
      This is a step closer. It exits the loop and prints the data ($read) to the terminal window.

      Problem is, i am no longer seeing all of the data. With the original code from the first post I saw all of the data. The only problem was that it was not leaving the while loop after reading all of the data in. Now it seems to be leaving off the last few lines (i'm sending 14 lines of text through and only seeing 9 being printed to the terminal)
        I have no real way to determine when the data is finished being read, other than there is nothing else coming in.
        In that case, if you think about it logically, there is no reliable way for your server to know when the client has finished sending. All proper network protocols give some way for the server to know, eg, client closes connection, client sends an agreed, fixed size of data, client sends a terminator code (\r\n in HTTP), client sends a header that contains the length of the rest of the message etc.

        I think you need to rethink your protocol.

        Dave.

Re: Sockets + Read
by Codon (Friar) on Aug 17, 2005 at 23:21 UTC

    Try unbuffering your filehandle ($socket). You may not be looping because you aren't getting enough data to fill your buffer.

    Really, this is all conjecture, though.

    Ivan Heffner
    Sr. Software Engineer, DAS Lead
    WhitePages.com, Inc.

      Sockets are unbuffered by default, FYI. (:

      - tye        

Re: Sockets + Read (sysread)
by tye (Sage) on Aug 17, 2005 at 23:26 UTC

    Try sysread.

    My guess is that read gets fewer than 1024 bytes from its first call to the underlying 'read' routine and then tries to read more data to fulfill your whole request.

    But that's mostly a guess and I'd've guessed that read wouldn't do that, but it fits your problem description.

    - tye        

      sysread has the same result.

      I tried that before posting. Should have mentioned that.
Re: Sockets + Read
by Roger (Parson) on Aug 18, 2005 at 00:32 UTC
    Firstly, the socket stream you have opened is most likely in blocked mode, which means your server trying to access the socket is blocked until there is data coming in from the socket.

    Secondly, you are reading the socket incorrectly. If should be
    while (read($client,$buffer,1024) == 1024) { # loop only if the incoming data is more than 1k $read .= $buffer; } # at this point, the buffer contains data less than 1k # this is the last read done by the while loop. $read .= $buffer;