17.19.3. Discussion
Although you can use select to manage input coming
at you from multiple directions, there are many tricks and traps. For
example, you can't use <> to read a line of
input, because you never know whether the client has sent a full line
yet (or will ever finish sending a line). You can't
print to a socket without the risk of the output
buffer being full and your process blocking. You need to use
non-blocking I/O and maintain your own buffers, and, consequently,
life rapidly becomes unmanageably complex.
Fortunately, we have a way of hiding complexity: modules. The
IO::Multiplex module from CPAN takes care of non-blocking I/O and
select for you. You tell it which filehandles to
watch, and it tells you when new data arrives. You can even
print to the filehandles, and it'll buffer and
non-blockingly output it. An IO::Multiplex object manages a pool of
filehandles.
Use the add method to tell IO::Multiplex to manage
a filehandle. This enables non-blocking I/O and disables the stdio
buffering. When IO::Multiplex receives data on one of its managed
filehandles, it calls a mux_input method on an
object or class of your choosing. Specify where
mux_input is by passing a package name (if your
callback is a class method) or object value (if your callback is an
object method) to the IO::Multiplex
set_callback_object method. In the example in the
Solution, we pass in the current package name so that IO::Multiplex
will call the current package's mux_input method.
Your mux_input callback is called with four
parameters: the object or package name that you gave to
set_callback_object, the IO::Multiplex object that
dispatched the callback, the filehandle from which data was received,
and a reference to the input buffer. The callback should delete data
from the buffer once it has been processed. For example, to process
line by line:
sub mux_input {
my ($obj, $mux, $fh, $buffer) = @_;
my ($line) = $$buffer =~ s{^(.*)\n}{ } or return;
# ...
}
To test this out, run the server in one window, then start a few
clients in other windows. Type something into one and see what
appears in the others.