Advanced Perl Programming

Advanced Perl ProgrammingSearch this book
Previous: 12.4 Real-World ServersChapter 12
Networking with Sockets
Next: 12.6 Prebuilt Client Modules
 

12.5 IO Objects and Filehandles

Perl supports the BSD socket call, which returns a filehandle, as open does for files and pipes. This filehandle can be used as an argument for all the built-in input-output operators: <> , read, sysread, print, write, syswrite, and so on. In addition, it can be used by socket-specific functions such as send, recv, and setsockopt.

The IO::Socket module's new method returns an object that can also be used as a parameter to these I/O routines. Internally, it calls socket and uses the typeglob corresponding to the filehandle to store other attributes; we described this hideous-looking trick in Section 8.1, "Efficient Attribute Storage". In other words, its return value is the same object that was given to socket, which is why it does not matter to the I/O operators which option you choose. My recommendation is to go for the considerably easier to use IO::Socket option.

IO::Select is another story, however. If performance is absolutely crucial, you may prefer to do yourself what IO::Select implements:

$r_bitset = $w_bitset = $e_bitset = '';
# Monitor $sock1 for reading
vec($r_bitset, $sock1->fileno(), 1) = 1;
# Monitor $sock2 for writing
vec($w_bitset, $sock2->fileno(), 1) = 1;
# Monitor both for errors
$e_bitset = $r_bitset | $w_bitset;

($nfound, $timeleft) = 
    select ($r_bitset, $w_bitset, $e_bitset, $timeout);

The native select function requires three bit vectors representing collections of open files, sockets, or pipes. Each bit in these bit sets corresponds to an integer file descriptor, which in turn is tracked by the appropriate filehandles or IO objects. The fileno() method of IO::Socket, or the built-in function, fileno, can be used to retrieve this number. The rest is simple: we create three bit sets, for checking readability, writability, and error conditions, and use vec to set the appropriate bits in each bit set. Before select returns, it modifies the bit sets to indicate which file descriptors are ready for doing input or output.

Because these bit sets are modified, we have to construct them all over again before going back to select, which gets to be somewhat expensive. Instead, a common technique is to make a copy of these sets before getting them clobbered by select:

# Set up $r_bitset and $w_bitset once
...

while (1) {
    ($nfound, $timeout) = select ($r_copy = $r_bitset, 
                                  $w_copy = $w_bitset, 
                                  $e_copy = $e_bitset, $timeout);

    # Check $r_copy, $w_copy for readiness ...
}

Note that the assignment happens before select gets control, and select sees only $r_copy, $w_copy, and $e_copy, which it feels free to modify.

The only place where we really save time over using IO::Select is that we don't have to make a list of ready filehandles; we can process the bit set directly. For the applications I have built, this marginal gain in efficiency is not worth it, so I use IO::Select.


Previous: 12.4 Real-World ServersAdvanced Perl ProgrammingNext: 12.6 Prebuilt Client Modules
12.4 Real-World ServersBook Index12.6 Prebuilt Client Modules