AnyEvent

 view release on metacpan or  search on metacpan

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

do not want to wait for that by blocking.

Idle watchers invoke their callback when the event loop has handled all
outstanding events, polled for new events and didn't find any, i.e., when
your process is otherwise idle. They are useful if you want to do some
non-trivial data processing that can be done when your program doesn't
have anything better to do.

All these watcher types are described in detail in the main L<AnyEvent>
manual page.

Sometimes you also need to know what the current time is: C<<
AnyEvent->now >> returns the time the event toolkit uses to schedule
relative timers, and is usually what you want. It is often cached (which
means it can be a bit outdated). In that case, you can use the more costly
C<< AnyEvent->time >> method which will ask your operating system for the
current time, which is slower, but also more up to date.


=head1 Network programming and AnyEvent

So far you have seen how to register event watchers and handle events.

This is a great foundation to write network clients and servers, and might
be all that your module (or program) ever requires, but writing your own
I/O buffering again and again becomes tedious, not to mention that it
attracts errors.

While the core L<AnyEvent> module is still small and self-contained,
the distribution comes with some very useful utility modules such as
L<AnyEvent::Handle>, L<AnyEvent::DNS> and L<AnyEvent::Socket>. These can
make your life as a non-blocking network programmer a lot easier.

Here is a quick overview of these three modules:

=head2 L<AnyEvent::DNS>

This module allows fully asynchronous DNS resolution. It is used mainly by
L<AnyEvent::Socket> to resolve hostnames and service ports for you, but is
a great way to do other DNS resolution tasks, such as reverse lookups of
IP addresses for log files.

=head2 L<AnyEvent::Handle>

This module handles non-blocking IO on (socket-, pipe- etc.) file handles
in an event based manner. It provides a wrapper object around your file
handle that provides queueing and buffering of incoming and outgoing data
for you.

It also implements the most common data formats, such as text lines, or
fixed and variable-width data blocks.

=head2 L<AnyEvent::Socket>

This module provides you with functions that handle socket creation
and IP address magic. The two main functions are C<tcp_connect> and
C<tcp_server>. The former will connect a (streaming) socket to an internet
host for you and the later will make a server socket for you, to accept
connections.

This module also comes with transparent IPv6 support, this means: If you
write your programs with this module, you will be IPv6 ready without doing
anything special.

It also works around a lot of portability quirks (especially on the
windows platform), which makes it even easier to write your programs in a
portable way (did you know that windows uses different error codes for all
socket functions and that Perl does not know about these? That "Unknown
error 10022" (which is C<WSAEINVAL>) can mean that our C<connect> call was
successful? That unsuccessful TCP connects might never be reported back
to your program? That C<WSAEINPROGRESS> means your C<connect> call was
ignored instead of being in progress? AnyEvent::Socket works around all of
these Windows/Perl bugs for you).

=head2 Implementing a parallel finger client with non-blocking connects
and AnyEvent::Socket

The finger protocol is one of the simplest protocols in use on the
internet. Or in use in the past, as almost nobody uses it anymore.

It works by connecting to the finger port on another host, writing a
single line with a user name and then reading the finger response, as
specified by that user. OK, RFC 1288 specifies a vastly more complex
protocol, but it basically boils down to this:

   # telnet freebsd.org finger
   Trying 8.8.178.135...
   Connected to freebsd.org (8.8.178.135).
   Escape character is '^]'.
   larry
   Login: lile                             Name: Larry Lile
   Directory: /home/lile                   Shell: /usr/local/bin/bash
   No Mail.
   Mail forwarded to: lile@stdio.com
   No Plan.

So let's write a little AnyEvent function that makes a finger request:

   use AnyEvent;
   use AnyEvent::Socket;

   sub finger($$) {
      my ($user, $host) = @_;

      # use a condvar to return results
      my $cv = AnyEvent->condvar;

      # first, connect to the host
      tcp_connect $host, "finger", sub {
         # the callback receives the socket handle - or nothing
         my ($fh) = @_
            or return $cv->send;

         # now write the username
         syswrite $fh, "$user\015\012";

         my $response;

         # register a read watcher
         my $read_watcher; $read_watcher = AnyEvent->io (
            fh   => $fh,

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

   }

This means you can queue as many requests as you want, and while
AnyEvent::Handle goes through its read queue to handle the response data,
the other side can work on the next request - queueing the request just
appends some data to the write queue and installs a handler to be called
later.

You might ask yourself how to handle decisions you can only make I<after>
you have received some data (such as handling a short error response or a
long and differently-formatted response). The answer to this problem is
C<unshift_read>, which we will introduce together with an example in the
coming sections.

=head3 Using C<http_get>

Finally, here is how you would use C<http_get>:

   http_get "www.google.com", "/", sub {
      my ($response, $header, $body) = @_;

      print
         $response, "\n",
         $body;
   };

And of course, you can run as many of these requests in parallel as you
want (and your memory supports).

=head3 HTTPS

Now, as promised, let's implement the same thing for HTTPS, or more
correctly, let's change our C<http_get> function into a function that
speaks HTTPS instead.

HTTPS is a standard TLS connection (B<T>ransport B<L>ayer
B<S>ecurity is the official name for what most people refer to as C<SSL>)
that contains standard HTTP protocol exchanges. The only other difference
to HTTP is that by default it uses port C<443> instead of port C<80>.

To implement these two differences we need two tiny changes, first, in the
C<connect> parameter, we replace C<http> by C<https> to connect to the
https port:

         connect  => [$host => 'https'],

The other change deals with TLS, which is something L<AnyEvent::Handle>
does for us if the L<Net::SSLeay> module is available. To enable TLS
with L<AnyEvent::Handle>, we pass an additional C<tls> parameter
to the call to C<AnyEvent::Handle::new>:

         tls      => "connect",

Specifying C<tls> enables TLS, and the argument specifies whether
AnyEvent::Handle is the server side ("accept") or the client side
("connect") for the TLS connection, as unlike TCP, there is a clear
server/client relationship in TLS.

That's all.

Of course, all this should be handled transparently by C<http_get>
after parsing the URL. If you need this, see the part about exercising
your inspiration earlier in this document. You could also use the
L<AnyEvent::HTTP> module from CPAN, which implements all this and works
around a lot of quirks for you too.

=head3 The read queue - revisited

HTTP always uses the same structure in its responses, but many protocols
require parsing responses differently depending on the response itself.

For example, in SMTP, you normally get a single response line:

   220 mail.example.net Neverusesendmail 8.8.8 <mailme@example.net>

But SMTP also supports multi-line responses:

   220-mail.example.net Neverusesendmail 8.8.8 <mailme@example.net>
   220-hey guys
   220 my response is longer than yours

To handle this, we need C<unshift_read>. As the name (we hope) implies,
C<unshift_read> will not append your read request to the end of the read
queue, but will prepend it to the queue instead.

This is useful in the situation above: Just push your response-line read
request when sending the SMTP command, and when handling it, you look at
the line to see if more is to come, and C<unshift_read> another reader
callback if required, like this:

   my $response; # response lines end up in here

   my $read_response; $read_response = sub {
      my ($handle, $line) = @_;

      $response .= "$line\n";

      # check for continuation lines ("-" as 4th character")
      if ($line =~ /^...-/) {
         # if yes, then unshift another line read
         $handle->unshift_read (line => $read_response);

      } else {
         # otherwise we are done

         # free callback
         undef $read_response;
         
         print "we are don reading: $response\n";
      }
   };

   $handle->push_read (line => $read_response);

This recipe can be used for all similar parsing problems, for example in
NNTP, the response code to some commands indicates that more data will be
sent:

   $handle->push_write ("article 42");

   # read response line



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