POE Explained... sort of. part 2 - events!!

xsawyerx on 2009-01-19T09:22:33

(Sorry for the massive delay in posting)




I don't know if I'll keep up the $num_of_exclamation_marks = $no_of_part title thing, but this subject is perhaps the hardest thing to understand when approaching POE. If you heard about event-based programming, and you figure "okay that's simple enough, I get it" then you probably don't!

The problem is that even though we figure it's a pretty basic concept (and really, it is), it's harder to understand what it means. What it really means is that you need to think differently. Understanding the idea vs. thinking differently.

Anyway, event-based programming is basically saying that a function is called only when an event happens, and not because the next line of code has been issued. You define events and what happens when an event occurs. That's when callbacks become useful. You can define that if the event falling_off_the_chair happens, you provide a callback (AKA code reference) to sub { print "hahaha\n"; } .

An example would help understand better:
Imagine a web server. The web server takes requests from browsers (or rather, clients) that want certain pages. It listens for incoming connections and whenever a connection arrives, he asks them "What the $@#* do you want?" and they say "give me that $!#%&*^ page over there!" and he goes to get the page, when he gets there, he (the server) gives the client the page and says "here you go, now take it and shove it up your %!@" and closes the connection to him. Web serving is a very violent profession, as you can tell.

Looking at the example, we see several events (and a few places to get counseling), which are:
  • a connection was made - a client connected to our socket
  • a request by that client was made
  • after being asked for a page, we try and reach it - reaching it is an event
  • the client confirming that he got the page
  • the connection closes

In event-based programming, we set up functions (either as subroutines at the top/bottom or straight away as anonymous subroutines) and then we set up whatever listens and provide it with references to the subroutines we wrote in case of certain events.

For the webserver, we'll have to write small functions in certain cases:
sub incoming_client {
    my $client = shift;
    print_to_client( $client, "yo yo yo. what page will you be askingz for?" );
}

sub asked_for_page { my ( $client, $request ) = @_; my $page = get_page($request); give_client_the_page( $client, $page ); }

sub accept_thankyou { my $client = shift; print_to_client( $client, "no, thank you!\n" ); }
Now this won't help us much if no one is going to be waiting for incoming connections, right? So we need to set up a TCP server, that accepts connections and forwards it according to the event. Obviously, the TCP server will have to understand what each event means. For example, if a client sends (using HTTP) a code that requests a file, our TCP server will need to say "oh oh, it's trying to get a file, I'll forward it to the correct subroutine". So, we'll use the fictional TCP server Sawyers::TCP::Server::That::Understands::HTTP. Yes, I like lots of namespaces. Dont::Event::Get::Me::Started.

This is the code for starting the TCP server and telling it what to do in any event:
use Sawyers::TCP::Server::That::Understands::HTTP;

my $server = Sawyers::TCP::Server::That::Understands::HTTP; $server->set_up_events( { incoming_connection => \&incoming_client, incoming_request => \&asked_for_page, closing_connection => \&accept_thankyou, echo_hello => sub { print "hi!\n"; }, } );

$server->start;

print "yay!\n";
Now, the trick here is that any code that comes after the $server->start won't be executed. Why? Simple, because $server will be running forever. Keeps an open connection and keeps waiting for events. So, there is really very little point waiting for the "yay" line, because it won't be there. Unless we set up an event that closes $server and when it will be closed, the remaining lines of code will run.

Any questions?


HTTP servers just wait

rcaputo on 2009-01-19T19:42:12

Unlike many other protocols, HTTP servers don't transmit a banner when clients connect. They just quietly sit there waiting for the client's request.

2 fold answer

xsawyerx on 2009-01-20T08:14:41

1. Fair enough. Perhaps HTTP server wasn't the best example for multi-events, since it also doesn't have a lot of events.
2. MY HTTPD WILL HAVE A BANNER, albeit I might have to write a new HTTP protocol...

BTW, thanks so much for all the help on #poe a while ago, this is what encouraged me to write these short articles and helped me understand POE altogether!

Re:HTTP servers just wait

Alias on 2009-01-20T12:56:51

The event is probably worth still having through, because once the connection is created, the server might need to do some internal accounting related to the connection. For example, firing off a new child process if we're getting close to running out of available children to handle connections (although in this case it's async so you wouldn't do that anyways).

But you get what I mean.

Re:HTTP servers just wait

xsawyerx on 2009-01-20T13:30:59

It could check the incoming client's IP against an ACL, and decide to refuse it before even getting the request. Sort of like ACL blocking pre-HTTP but post-iptables/kernel-socket-connection.