Using Nonblocking Handles


 
Network Programming with Perl
By Lincoln  D.  Stein
Slots : 1
Table of Contents
Chapter  13.   Nonblocking I/O

    Content

As soon as you use nonblocking filehandles, things become a bit more complex because of the several possible outcomes of calling sysread () and syswrite() .

sysread() on Nonblocking Filehandles

When you use sysread() with a nonblocking filehandle, the following outcomes are possible:

  1. If you request N bytes of data and at least N are available, then sysread() fills the scalar buffer you provide with N bytes and returns the number of bytes read.

  2. If you request N bytes of data and fewer bytes are available (but at least 1), then sysread() fills the scalar buffer with the available bytes and returns the number read.

  3. If you request N bytes of data and no bytes are available, then sysread() returns undef and sets $! to EWOULDBLOCK .

  4. At the end of file, sysread() returns numeric 0.

  5. For all other error conditions, sysread() returns undef and sets $! to the appropriate error code.

When reading from nonblocking handles, you must correctly distinguish the end-of-file condition from EWOULDBLOCK . The first will return numeric 0 from sysread() , and the latter will return undef . Code to read from a nonblocking socket should look something like this:

 my $rc = sysread(SOCK,$data,$bytes); if (defined $rc) { # non-error    if ($rc > 0) {  # read successful       # handle a successful read    } else {        # end of file       close SOCK;       # handle end of file    }     } elsif ($! == EWOULDBLOCK) { # got a would block error    # handle blocking, probably just by trying again } else {    # unexpected error    die "sysread() error: $!"; } 

This code fragment calls sysread() and stores its result code into the variable $rc . We first check whether the result code is defined. If so, we know that the call was successful. A positive result code indicates some number of bytes was read, while a numeric flags the end-of-file condition. We handle both cases in whatever way is appropriate for the application.

If the result code is undefined, then some error occurred and the specific error code can be found in $! . We first check whether $! is numerically equal to EWOULDBLOCK , and if so handle the error. In most cases, we just jump back to the top of the program's main loop and try the read again later. In the case of other errors, we die with an error message.

syswrite() on Nonblocking Filehandles

The following outcomes are possible when using syswrite() with nonblocking filehandles:

  1. A complete write If you try to write N bytes of data and the filehandle can accept them all, it will do so and return the count as its function result.

  2. A partial write If you try to write N bytes of data and the filehandle can only accept fewer (but at least 1), it will write as much as it can to the handle's send buffer and return the number of bytes actually written.

  3. A write that would block If you try to write N bytes of data and the filehandle cannot accept any, then syswrite() will return immediately with a function result of undef and set $! to EWOULDBLOCK .

  4. A write error On other errors, syswrite() will return undef and set $! to the appropriate error code. The most typical write error is EPIPE , indicating that the remote host has stopped reading.

The tricky part of writing to a nonblocking socket is handling partial writes . You must remember where the write left off and try to send the rest of the data later. Here's the skeleton of the code you might use to deal with this:

 my $rc = syswrite(SOCK,$data); if ($rc > 0) {  # some data written    substr($data,0,$rc) = ' '; # truncate buffer } elsif ($! == EWOULDBLOCK) {   # would block, not an error   # handle blocking, probably just by trying again later. } else {   die "error on syswrite(): $!"; } 

We call syswrite() to write out the contents of the scalar variable $data and check the call's result code. If at least one byte was written, then we truncate the variable using this trick:

 substr($data,0,$rc) = ' '; 

substr() is one of several Perl functions that can be used on the left side of an assignment statement. Everything from the beginning of the number of bytes written is replaced with an empty string, leaving the variable containing just the data that wasn't written. In the case in which syswrite() was able to write the entire contents of the variable, this substr() expression leaves $data empty.

If the result code is or undef , then we again compare the error code to EWOULDBLOCK and take appropriate action, typically returning to the program's main loop and trying the write again later. On other errors, we die with an error message.

This code fragment needs to be executed repeatedly until $data is entirely written. You could just put a loop around the whole thing:

 while (length $data > 0) {    my $rc = syswrite(SOCK,$data);    # ... etc.... } 

However, this is not terribly efficient because repeated writes to the same socket may just result in the same EWOULDBLOCK error. It's best to incorporate the syswrite() call into a select() loop and to do other work while waiting for the socket to become ready to accept more data. The next section shows how to do this.


   
Top


Network Programming with Perl
Network Programming with Perl
ISBN: 0201615711
EAN: 2147483647
Year: 2000
Pages: 173

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net