in reply to sysread and syswrite in tcp sockets

If you use sysread you must expect partial reads -- see the fine documentation. (Update: sorry, the documentation doesn't tell you this... I felt sure it did... I feel sure it should. Update 2: I am grateful to brother ikegami for pointing out ( see below) the significance of the word Attempts, which I am ashamed to admit I had missed.)

You could try plain read, which is less "clever".

Or you wrap a loop around the sysread, eg:

my $rc ; my $buff = '' ; do { $rc = sysread(FH, $buff, 5000000, length($buff)) ; } while ($rc +) ;
which will suck away at FH until it hits eof ($rc == 0) or hits some error (!defined($rc)). (Noting that if the FH is set to be non-blocking you can get "soft" EAGAIN error(s)...)

Replies are listed 'Best First'.
Re^2: sysread and syswrite in tcp sockets
by ikegami (Patriarch) on Dec 22, 2008 at 17:06 UTC

    It is documented in the very first word: (emphasis mine)

    Attempts to read LENGTH bytes of data into variable SCALAR from the specified FILEHANDLE

    sysread returns what's available

    • when the end of file is reached
    • when there's fewer than LENGTH bytes available from a pipe or socket
    • when the call is interrupted by a signal

    None of those conditions are considered errors.

Re^2: sysread and syswrite in tcp sockets
by rustybar (Novice) on Dec 22, 2008 at 12:55 UTC
    Hi, Thanks for the reply. Actually for the client program, I did use print to send username and password to the server first for authentication before receiving the file. Will it help if I change print to syswrite instead? I did try before but it doesn't work too.
    Updated Client program: create_socket #function to establish connection with server print $sock, <username>; sleep(1); #to allow a pause so that username and pwd are 2 streams print $sock <pwd>; while($len = sysread($sock, $buffer, 500000000)) { createFile("<filename>", $buffer, $len, 0); #processFile; }

      I'm not sure I understand the problem here... You're printing the <username> to a socket, sleeping for 1 second, and then printing the <pwd>. I cannot tell whether the other end will see these as separate or not -- though it is likely if client and server are the same machine.

      sysread will return what has been received so far, or will wait until at least 1 byte is available -- so if the receiver is fast enough it will effectively see each packet as it arrives (all the bytes of a packet become available at the same time).

      read, on the other hand, will collect data from incoming packets until it has the number of bytes you asked for, or the connection is closed.

      At the sender end we have: (a) any buffering done at the Perl level (in particular PerlIO); and (b) any buffering done at the socket level.

      Stuff output by print will be buffered by PerlIO. If 'autoflush' is set, then at the end of a print statement, the buffer will be flushed to the socket. But syswrite bypasses the PerlIO buffering, and sends stuff directly to the socket. You will find that IO::Socket::INET sets 'autoflush' by default -- so by default the difference between print and syswrite is small, except that with syswrite you have to cope with partial writes !

      Now, there's nothing in TCP that absolutely requires packets to be sent as soon as there is data ready to go, but generally it will do so unless data previously sent has not yet been acknowledged (this is Nagle's algorithm). So, whether the result of separate print or syswrite operations arrive together depends to some extent on the speed of the network.

      As far as you fragment of code is concerned,

      while($len = sysread($sock, $buffer, 500000000)) { createFile("<filename>", $buffer, $len, 0); #processFile; }
      this will (if it is fast enough) createFile() for each packet received... I suspect that isn't what you had in mind ?