AnyEvent

 view release on metacpan or  search on metacpan

lib/AnyEvent/Intro.pod  view on Meta::CPAN

"continuation" is simply the way the program continues - normally at the
next line after some statement (the exception is loops or things like
C<return>). When we are interested in events, however, we instead specify
the "continuation" of our program by passing a closure, which makes that
closure the "continuation" of the program.

The C<tcp_connect> call is like saying "return now, and when the
connection is established or the attempt failed, continue there".

Now let's look at the callback/closure in more detail:

         # the callback receives the socket handle - or nothing
         my ($fh) = @_
            or return $cv->send;

The first thing the callback does is to save the socket handle in
C<$fh>. When there was an error (no arguments), then our instinct as
expert Perl programmers would tell us to C<die>:

         my ($fh) = @_
            or die "$host: $!";

While this would give good feedback to the user (if he happens to watch
standard error), our program would probably stop working here, as we never
report the results to anybody, certainly not the caller of our C<finger>
function, and most event loops continue even after a C<die>!

This is why we instead C<return>, but also call C<< $cv->send >> without
any arguments to signal to the condvar consumer that something bad has
happened. The return value of C<< $cv->send >> is irrelevant, as is
the return value of our callback. The C<return> statement is used for
the side effect of, well, returning immediately from the callback.
Checking for errors and handling them this way is very common, which is
why this compact idiom is so handy.

As the next step in the finger protocol, we send the username to the
finger daemon on the other side of our connection (the kernel.org finger
service doesn't actually wait for a username, but the net is running out
of finger servers fast):

         syswrite $fh, "$user\015\012";

Note that this isn't 100% clean socket programming - the socket could,
for whatever reasons, not accept our data. When writing a small amount
of data like in this example it doesn't matter, as a socket buffer is
almost always big enough for a mere "username", but for real-world
cases you might need to implement some kind of write buffering - or use
L<AnyEvent::Handle>, which handles these matters for you, as shown in the
next section.

What we I<do> have to do is implement our own read buffer - the response
data could arrive late or in multiple chunks, and we cannot just wait for
it (event-based programming, you know?).

To do that, we register a read watcher on the socket which waits for data:

         my $read_watcher; $read_watcher = AnyEvent->io (
            fh   => $fh,
            poll => "r",

There is a trick here, however: the read watcher isn't stored in a global
variable, but in a local one - if the callback returns, it would normally
destroy the variable and its contents, which would in turn unregister our
watcher.

To avoid that, we refer to the watcher variable in the watcher callback.
This means that, when the C<tcp_connect> callback returns, perl thinks
(quite correctly) that the read watcher is still in use - namely inside
the inner callback - and thus keeps it alive even if nothing else in the
program refers to it anymore (it is much like Baron Münchhausen keeping
himself from dying by pulling himself out of a swamp).

The trick, however, is that instead of:

   my $read_watcher = AnyEvent->io (...

The program does:

   my $read_watcher; $read_watcher = AnyEvent->io (...

The reason for this is a quirk in the way Perl works: variable names
declared with C<my> are only visible in the I<next> statement. If the
whole C<< AnyEvent->io >> call, including the callback, would be done in
a single statement, the callback could not refer to the C<$read_watcher>
variable to C<undef>ine it, so it is done in two statements.

Whether you'd want to format it like this is of course a matter of style.
This way emphasizes that the declaration and assignment really are one
logical statement.

The callback itself calls C<sysread> for as many times as necessary, until
C<sysread> returns either an error or end-of-file:

            cb   => sub {
               my $len = sysread $fh, $response, 1024, length $response;

               if ($len <= 0) {

Note that C<sysread> has the ability to append data it reads to a scalar
if we specify an offset, a feature which we make use of in this example.

When C<sysread> indicates we are done, the callback C<undef>ines
the watcher and then C<send>s the response data to the condition
variable. All this has the following effects:

Undefining the watcher destroys it, as our callback was the only one still
having a reference to it. When the watcher gets destroyed, it destroys the
callback, which in turn means the C<$fh> handle is no longer used, so that
gets destroyed as well. The result is that all resources will be nicely
cleaned up by perl for us.

=head3 Using the finger client

Now, we could probably write the same finger client in a simpler way if
we used C<IO::Socket::INET>, ignored the problem of multiple hosts and
ignored IPv6 and a few other things that C<tcp_connect> handles for us.

But the main advantage is that we can not only run this finger function in
the background, we even can run multiple sessions in parallel, like this:

   my $f1 = finger "kuriyama", "freebsd.org";



( run in 0.943 second using v1.01-cache-2.11-cpan-39bf76dae61 )