Most programs only deal with one user at a time. If the user isn't
ready, there's nothing else the program has to do. So when a Perl
program reads from <STDIN> and the user hasn't typed anything, it
stops until the user is ready. (This is called blocking I/O.)
This doesn't work for a chat server, because users don't take turns.
One user may have gone off to get some coffee, but the others are
still typing, and the server has to deliver their messages.
One way to solve this problem is to create an entity for each user,
either by using fork() to create another process, or using
multithreaded programming (which, unfortunately, isn't available for Perl yet). The
system might be serving multiple users, but each user still has her own entity
that can wait for her command.
Processes, however, are expensive so this approach rapidly becomes inefficient
as more people log in to the chat system. It's much better to have one process
that handles everyone's requests. What we really need is a way to find out who's
ready to be served without ever waiting (unless there really isn't anyone who
wants to chat). This is what the select() function does.
Like the socket functions, select() traditionally has been hard to use,
so most programmers avoided it if they could. Perl, however,
has an object-oriented wrapper around it now called IO::Select, which makes
it much easier to use.
Suppose we want to wait on two sockets, $thing1
and $thing2. First we create a select() object that contains the
two sockets:
$select = IO::Select->new($thing1,$thing2);
Next, whenever we want to know who has data for us we ask the select
object:
my @ready = $select->can_read;
This call will wait until either $thing1 or $thing2 is ready, and
will return an array containing the socket that is. (If they're both
ready, @ready will contain both sockets.)
Once we have the ready sockets, we in turn can read from each of them
to find out what they sent:
for $socket (@ready) {
$socket->recv($line,80);
if($line eq "") { die "they hung up on me"; }
print "someone sent $line. Sending it back.\n";
$socket->send($line) or die "hey, where did they go?";
}
next page»