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

I have a tcp server script executed through inetd. A variable length string of switches and data is passed by the client. The server simply reads from <STDIN>. The server works most of the time but sometimes it only reads a portion of the string. I have verified that the entire string is being submitted by the client. Below is a simplistic example of the server code:

$string = <STDIN>;
print $string; #Send the result back to the client
exit; #Close the connection

Though I am not worthy, any suggestions? Thanks.

Evilstevel

Replies are listed 'Best First'.
Re: Server script through inetd
by traveler (Parson) on Jul 25, 2001 at 19:46 UTC
    Assuming you don't have $/ set, the problem may be that perl is receiving a partial line from the read or recv it uses. Recall that even though it looks like a read from a keyboard, it is reading from a socket. The TCP protocol does not necessarily deliver data in the chunks (e.g. lines) in which it was sent. There are no data boundries in TCP (use UDP for that). While the camel book examples just use
    while($line = <SOCK>)
    to read, they read small messages.

    In general, when you read from a TCP socket you need to be sure you got a whole message (a line in your case) and continue reading until you can verify that you got the whole message.

    You can test with something like this:

    $| = 1; # remove buffering while($input = <STDIN>){ # maybe process the input print $input; }
    --traveler </code>

      I don't believe that is the problem. If Perl gets partial data from a socket and that partial data doesn't contain the current value of $/, then <STDIN> is going to issue another read until it either gets a string that contains the current value of $/ or it gets end-of-file. (Well, that is my impression and testing confirms it but the perl source code involved is quite complex with lots of possible routes through the code depending on #ifdefs and big ifs, so there may be some cases where this doesn't happen -- if so, I'd appreciate validation of this fact.)

      But, in general, this feature usually ends up being a good reason to not use <SOCK> to read from sockets. Certainly, if you do use <SOCK> to read from sockets, be sure to have $/ set appropriately.

      For this case, I would think that "appropriately" would mean having $/ set to undef so that <STDIN> reads until end-of-file. But that strategy won't work unless the client requests that end-of-file be sent by using shutdown. But then, if the client doesn't use shutdown than the server has no reliable way to determine when all of the data has been received and it would have to resort to some sort of timeout logic.

      evilstevel, feel free to provide more details if our guessing hasn't helped yet. (:

              - tye (but my friends call me "Tye")
Re: Server script through inetd
by abstracts (Hermit) on Jul 26, 2001 at 02:58 UTC
    Hello,

    Did you not ask this same question yesterday. If you did not check the responses to that article, please do so now by following this link.

    Thanks,,,

    Aziz,,,

      Thanks Aziz.

      I could not find my original post yesterday, so I generated another one. I resolved my problem using one of your suggestions. I complicated things a bit by needing to encrypt the string sent by the client. The encrypted string provides a variety of characters so I "pack(u*, $string)" the string. Since "^end\n" is not something you will see in the uuencoded string, I attached it from the client and I used it to break from the loop:

      while ($string = <stdin>) {
      last if $string =~ /^end\n/;
      $msg .= $queuestr;
      }

      Thanks again for everyones input.

      evilstevel