AnyEvent
view release on metacpan or search on metacpan
lib/AnyEvent/Intro.pod view on Meta::CPAN
once and invoked your callback, they are dead and no longer do anything.
To get a repeating timer, such as a timer firing roughly once per second,
you can specify an C<interval> parameter:
my $once_per_second = AnyEvent->timer (
after => 0, # first invoke ASAP
interval => 1, # then invoke every second
cb => sub { # the callback to invoke
$cv->send;
},
);
=head3 More esoteric sources
AnyEvent also has some other, more esoteric event sources you can tap
into: signal, child and idle watchers.
Signal watchers can be used to wait for "signal events", which means
your process was sent a signal (such as C<SIGTERM> or C<SIGUSR1>).
Child-process watchers wait for a child process to exit. They are useful
when you fork a separate process and need to know when it exits, but you
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:
lib/AnyEvent/Intro.pod view on Meta::CPAN
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";
my $f2 = finger "icculus?listarchives=1", "icculus.org";
my $f3 = finger "mikachu", "icculus.org";
print "kuriyama's gpg key\n" , $f1->recv, "\n";
print "icculus' plan archive\n" , $f2->recv, "\n";
print "mikachu's plan zomgn\n" , $f3->recv, "\n";
It doesn't look like it, but in fact all three requests run in
parallel. The code waits for the first finger request to finish first, but
that doesn't keep it from executing them parallel: when the first C<recv>
call sees that the data isn't ready yet, it serves events for all three
requests automatically, until the first request has finished.
The second C<recv> call might either find the data is already there, or it
will continue handling events until that is the case, and so on.
By taking advantage of network latencies, which allows us to serve other
requests and events while we wait for an event on one socket, the overall
time to do these three requests will be greatly reduced, typically all
three are done in the same time as the slowest of the three requests.
By the way, you do not actually have to wait in the C<recv> method on an
AnyEvent condition variable - after all, waiting is evil - you can also
register a callback:
$f1->cb (sub {
my $response = shift->recv;
# ...
});
The callback will be invoked only when C<send> is called. In fact,
instead of returning a condition variable you could also pass a third
parameter to your finger function, the callback to invoke with the
response:
sub finger($$$) {
my ($user, $host, $cb) = @_;
How you implement it is a matter of taste - if you expect your function to
be used mainly in an event-based program you would normally prefer to pass
a callback directly. If you write a module and expect your users to use
it "synchronously" often (for example, a simple http-get script would not
really care much for events), then you would use a condition variable and
tell them "simply C<< ->recv >> the data".
=head3 Problems with the implementation and how to fix them
To make this example more real-world-ready, we would not only implement
some write buffering (for the paranoid, or maybe denial-of-service aware
security expert), but we would also have to handle timeouts and maybe
protocol errors.
Doing this quickly gets unwieldy, which is why we introduce
L<AnyEvent::Handle> in the next section, which takes care of all these
details for you and lets you concentrate on the actual protocol.
=head2 Implementing simple HTTP and HTTPS GET requests with AnyEvent::Handle
The L<AnyEvent::Handle> module has been hyped quite a bit in this document
so far, so let's see what it really offers.
As finger is such a simple protocol, let's try something slightly more
complicated: HTTP/1.0.
An HTTP GET request works by sending a single request line that indicates
what you want the server to do and the URI you want to act it on, followed
by as many "header" lines (C<Header: data>, same as e-mail headers) as
required for the request, followed by an empty line.
The response is formatted very similarly, first a line with the response
status, then again as many header lines as required, then an empty line,
followed by any data that the server might send.
Again, let's try it out with C<telnet> (I condensed the output a bit - if
you want to see the full response, do it yourself).
# telnet www.google.com 80
Trying 209.85.135.99...
Connected to www.google.com (209.85.135.99).
Escape character is '^]'.
GET /test HTTP/1.0
HTTP/1.0 404 Not Found
Date: Mon, 02 Jun 2008 07:05:54 GMT
Content-Type: text/html; charset=UTF-8
<html><head>
[...]
Connection closed by foreign host.
The C<GET ...> and the empty line were entered manually, the rest of the
telnet output is google's response, in this case a C<404 not found> one.
So, here is how you would do it with C<AnyEvent::Handle>:
sub http_get {
my ($host, $uri, $cb) = @_;
# store results here
my ($response, $header, $body);
( run in 0.661 second using v1.01-cache-2.11-cpan-39bf76dae61 )