ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/AnyEvent-MP/MP/Intro.pod
Revision: 1.19
Committed: Fri Aug 28 15:24:16 2009 UTC (14 years, 9 months ago) by elmex
Branch: MAIN
Changes since 1.18: +53 -0 lines
Log Message:
receiver example done.

File Contents

# User Rev Content
1 root 1.4 =head1 Message Passing for the Non-Blocked Mind
2 elmex 1.1
3 root 1.8 =head1 Introduction and Terminology
4 elmex 1.1
5 root 1.4 This is a tutorial about how to get the swing of the new L<AnyEvent::MP>
6 root 1.14 module, which allows us to transparently pass messages to our own process
7 root 1.8 and to other processes on another or the same host.
8 elmex 1.1
9 root 1.15 What kind of messages? Well, basically a message here means a list of Perl
10     strings, numbers, hashes and arrays, anything that can be expressed as a
11     L<JSON> text (as JSON is used by default in the protocol).
12 elmex 1.1
13 elmex 1.17 It's custom in L<AnyEvent::MP> to have a string which describes the type of the
14     message as first element (this is called a I<tag> in L<AnyEvent::MP>), as some
15     API functions (C<rcv>) support matching it directly. So supposedly you want to
16     send a ping message with your current time to something, this is how such a
17     message might look like (in Perl syntax):
18 elmex 1.1
19 elmex 1.17 ['ping', 1251381636]
20 elmex 1.7
21 elmex 1.17 And next you might ask: between which entities are those messages being
22     I<passed>? They are I<passed> between I<ports>. I<ports> are just sources and
23     destinations for messages. How do these ports relate to things you know? Well,
24     each I<port> belongs to a I<node>, and a I<node> is just the UNIX process that
25     runs your L<AnyEvent::MP> application.
26    
27     Each I<node> is distinguished from other I<nodes> running on the same host or
28     multiple hosts in a network by it's I<node ID>. A I<node ID> can be manually
29     assigned or L<AnyEvent::MP> will assign one it self for you.
30    
31 elmex 1.18 So, you might want to visualize it like this (setup is two nodes (more are of
32     course possible): Node C<A> (in UNIX process 7066) with ports C<ABC> and C<DEF>
33     and C<B> (in UNIX process 8321) with ports C<FOO> and C<BAR>).
34 elmex 1.17
35    
36     |- PID: 7066 -| |- PID: 8321 -|
37     | | | |
38     | Node ID: A | | Node ID: B |
39     | | | |
40     | Port ABC =|= <----\ /-----> =|= Port FOO |
41     | | X | |
42     | Port DEF =|= <----/ \-----> =|= Port BAR |
43     | | | |
44     |-------------| |-------------|
45    
46     The strings for the ports here are just for illustrative purposes. Even if in
47     reality I<ports> in L<AnyEvent::MP> are also identified by strings they can't
48     be choosen manually and are assigned randomly. These I<port ids> should also
49 elmex 1.18 not be used directly for other purposes than referring to an endpoint for
50 elmex 1.17 messages.
51    
52     The next sections will explain the API of L<AnyEvent::MP>. First the API is
53 elmex 1.18 laid out by simple examples. Later some more complex idioms are introduced,
54     which are maybe useful to solve some real world purposes.
55 elmex 1.17
56     # In this tutorial I'll show you how to write a simple chat server based on
57     # L<AnyEvent::MP>. This example is used because it nicely shows how to organise a
58     # simple application, but keep in mind that every node trusts any other, so this
59     # chat cannot be used to implement a real public chat server and client system,
60     # but it can be used to implement a distributed chat server for example.
61 root 1.8
62 elmex 1.16 =head1 Passing Your First Message
63    
64     As start lets have a look at the messaging API. The next example is just a
65     demo to show the basic elements of message passing with L<AnyEvent::MP>.
66     It shout just print: "Ending with: 123". So here the code:
67    
68     use AnyEvent;
69     use AnyEvent::MP;
70    
71     my $end_cv = AnyEvent->condvar;
72    
73     my $port = port;
74    
75     rcv $port, test => sub {
76     my ($data) = @_;
77     $end_cv->send ($data);
78     };
79    
80     snd $port, test => 123;
81    
82     print "Ending with: " . $end_cv->recv . "\n";
83    
84 elmex 1.17 It already contains most functions of the essential L<AnyEvent::MP> API.
85    
86     First there is the C<port> function which will create a I<port> and will return
87     it's I<port id>.
88    
89     That I<port id> can be used to send and receive messages. That I<port id> is a
90     simple string and can be safely passed to other I<nodes> in the network to
91     refer to that specific port (usually used for RPC, where you need to
92     tell the other end which I<port> to send the reply to).
93    
94     Next function is C<rcv>:
95 elmex 1.16
96 elmex 1.17 rcv $port, test => sub { ... };
97 elmex 1.16
98 elmex 1.17 It sets up a receiver callback on a specific I<port> which needs to be
99     specified as the first argument. The next argument, in this example C<test>, is
100     a I<tag> match. This means that whenever a message, with the first element
101     being the string C<tag>, is received the callback is called with the remaining
102     parts of that message.
103    
104     Messages can be send with the C<snd> function, which looks like this in the
105     example above:
106    
107     snd $port, test => 123;
108    
109     This will send the message C<['test', 123]> to the I<port> with the I<port id>
110     in C<$port>. The receiver got a I<tag> match on C<test> and will call the
111     callback with the first argument being the number C<123>.
112    
113     That callback then just passes that number on to the I<condition variable>
114     C<$end_cv> which will then pass the value to the print. But I<condition
115     variables> are out of the scope of this tutorial. So please consult the
116     L<AnyEvent::Intro> about them.
117    
118     But passing messages inside one process is boring, but before we can continue
119     and take the next step to interprocess message passing we first have to make
120     sure some things have been setup.
121    
122     =head1 System Requirements and System Setup
123    
124     Before we can start with real IPC we have to make sure some things work on your
125     system.
126    
127     First we have to setup a I<shared secret>: for two L<AnyEvent::MP> I<nodes> to
128     be able to communicate with each other and authenticate each other it is
129     necessary to setup the same I<shared secret> for both of them (or use TLS
130     certificates).
131    
132     The easiest way is to set this up is to use the F<aemp> utility:
133    
134     aemp gensecret
135    
136     This creates a F<$HOME/.perl-anyevent-mp> config file and generates a random
137     shared secret. You can copy this file to any other system and then communicate
138     over the network (via TCP) with it. You can also select your own shared secret
139     (F<aemp setsecret>) and for increased security requirements you can even create
140     a TLS certificate (F<aemp gencert>), causing connections to not just be
141     authenticated, but also to be encrypted.
142    
143     Connections will only be successful when the I<nodes> that want to connect to
144     each other have the same I<shared secret> (or successfully verify the TLS
145     certificate of the other side).
146    
147     B<If something does not work as expected, and for example tcpdump shows
148     that the connections are closed almost immediately, you should make sure
149     that F<~/.perl-anyevent-mp> is the same on all hosts/user accounts that
150     you try to connect with each other!>
151 elmex 1.16
152 elmex 1.18 Thats all for now, there is more fiddling around with the C<aemp> utility
153     later.
154    
155     =head1 Passing Messages Between Processes
156    
157     =head2 The Receiver
158    
159     Lets split the previous example up into two small programs. First the
160     receiver application:
161    
162     #!/opt/perl/bin/perl
163     use AnyEvent;
164     use AnyEvent::MP;
165     use AnyEvent::MP::Global;
166    
167     initialise_node "eg_simple_receiver";
168    
169     my $port = port;
170    
171     AnyEvent::MP::Global::register $port, "eg_receivers";
172    
173     rcv $port, test => sub {
174     my ($data, $reply_port) = @_;
175    
176     print "Received data: " . $data . "\n";
177     };
178    
179     AnyEvent->condvar->recv;
180    
181     =head3 AnyEvent::MP::Global
182    
183     Now, that wasn't too bad, was it? Ok, lets step through the new functions
184     and modules that have been used. For starters there is now an additional
185     module loaded: L<AnyEvent::MP::Global>.
186    
187     That module provides us with a I<global registry>, which lets us share data
188     among all I<nodes> in a network. Why do we need it you might ask?
189    
190     The I<port ids> are just random strings, assigned by L<AnyEvent::MP>. We can't
191     know those I<port ids> in advance, so we don't know which I<port id> to send
192     messages to if the message is to be passed between I<nodes> (or UNIX
193     processes). To find the right I<port> of another I<node> in the network we will
194     need to communicate that somehow to the sender. And exactly that is what
195     L<AnyEvent::MP::Global> provides.
196    
197     =head3 initialise_node And The Network
198    
199     Now, lets have a look at the next new thing, the C<initialise_node>:
200    
201     initialise_node "eg_simple_receiver";
202    
203     Before we are able to send messages to other nodes we have to initialise
204     ourself. The first argument, the string C<"eg_simple_receiver">, is called the
205     I<profile> of this node. A profile holds some information about the application
206     that is going to be a node in an L<AnyEvent::MP> network.
207    
208     Most importantly the profile allows you to set the I<node id> that your
209     application will use. You can also set I<binds> in the profile, meaning that
210     you can define TCP ports that the application will listen on for incoming
211     connections from other nodes of the network.
212    
213     Next you can configure I<seeds> in profile. A I<seed> is just a TCP endpoint
214     which tells the application where to find other nodes of it's network. To
215     explain this a bit more detailed we have to look at the topology of an
216     L<AnyEvent::MP> network. The topology is called a I<fully connected mesh>, here
217     an example with 4 nodes:
218    
219     N1--N2
220     | \/ |
221     | /\ |
222     N3--N4
223    
224     Now imagine another I<node> C<N5>. wants to connect itself to that network:
225    
226     N1--N2
227     | \/ | N5
228     | /\ |
229     N3--N4
230    
231     The new node needs to know the I<binds> of all of those 4 already connected
232     nodes. And exactly this is what the I<seeds> are for. Now lets assume that
233     the new node C<N5> has as I<seed> the TCP endpoint of the node C<N2>.
234     It then connects to C<N2>:
235    
236     N1--N2____
237     | \/ | N5
238     | /\ |
239     N3--N4
240    
241     C<N2> then tells C<N5> the I<binds> of the other nodes it is connected to,
242     and C<N5> builds up the rest of the connections:
243    
244     /--------\
245     N1--N2____|
246     | \/ | N5
247     | /\ | /|
248     N3--N4--- |
249     \________/
250    
251     Finished. C<N5> is now happily connected to the rest of the network.
252    
253 elmex 1.19 =head3 Setting Up The Profiles
254    
255     Ok, so much to the profile. Now lets setup the C<eg_simple_receiver> I<profile>
256     for later. For the receiver we just give the receiver a I<bind>:
257    
258     aemp profile eg_simple_receiver setbinds localhost:12266
259    
260     And while we are at it, just setup the I<profile> for the sender in the second
261     part of this example too. We will call the sender I<profile>
262     C<eg_simple_sender>. For the sender we will just setup a I<seed> to the
263     receiver:
264    
265     aemp profile eg_simple_sender setseeds localhost:12266
266    
267     You might wonder why we don't setup a I<bind> here. Well, there can be
268     exceptions to the I<fully> in the I<fully connected mesh> in L<AnyEvent::MP>.
269     If you don't configure a I<bind> for a node's profile it won't bind itself
270     somewhere. These kinds of I<nodes> will not be able to send messages to other
271     I<nodes> that also didn't I<bind> them self to some TCP address. For this
272     example, as well as some cases in the real world, we can live with this
273     limitation.
274    
275     =head3 Registering The Receiver
276    
277     Ok, where were we. We now discussed the basic purpose of L<AnyEvent::MP::Global>
278     and initialise_node with it's relations to profiles. We also setup our profiles
279     for later use and now have to continue talking about the receiver example.
280    
281     Lets look at the next undiscussed line(s) of code:
282    
283     my $port = port;
284     AnyEvent::MP::Global::register $port, "eg_receivers";
285    
286     The C<port> function already has been discussed. It just creates a new I<port>
287     and gives us the I<port id>. Now to the C<register> function of
288     L<AnyEvent::MP::Global>: The first argument is a I<port id> that we want to add
289     to a I<global group>, and it's second argument is the name of that I<global
290     group>.
291    
292     You can choose that name of such a I<global group> freely, and it's purpose is
293     to store a set of I<port ids>. That set is made available throughout the whole
294     L<AnyEvent::MP> network, so that each node can see which ports belong to that
295     group.
296    
297     The sender will later look for the ports in that I<global group> and send
298     messages to them.
299    
300     Last step in the example is to setup a receiver callback for those messages
301     like we have discussed in the first example. We again match for the I<tag>
302     C<test>. The difference is just that we don't end the application after
303     receiving the first message. We just infinitely continue to look out for new
304     messages.
305    
306 root 1.8 =head1 The Chat Client
307    
308     OK, lets start by implementing the "frontend" of the client. We will
309     develop the client first and postpone the server for later, as the most
310     complex things actually happen in the client.
311    
312     We will use L<AnyEvent::Handle> to do non-blocking IO read on standard
313     input (all of this code deals with actually handling user input, no
314     message passing yet):
315 elmex 1.7
316 root 1.8 #!perl
317 elmex 1.1
318     use AnyEvent;
319     use AnyEvent::Handle;
320    
321     sub send_message {
322     die "This is where we will send the messages to the server"
323     . "in the next step of this tutorial.\n"
324     }
325    
326     # make an AnyEvent condition variable for the 'quit' condition
327     # (when we want to exit the client).
328     my $quit_cv = AnyEvent->condvar;
329    
330     my $stdin_hdl = AnyEvent::Handle->new (
331 root 1.8 fh => *STDIN,
332     on_error => sub { $quit_cv->send },
333     on_read => sub {
334 elmex 1.1 my ($hdl) = @_;
335    
336     $hdl->push_read (line => sub {
337     my ($hdl, $line) = @_;
338    
339     if ($line =~ /^\/quit/) { # /quit will end the client
340     $quit_cv->send;
341     } else {
342     send_message ($line);
343     }
344     });
345     }
346     );
347    
348     $quit_cv->recv;
349    
350 root 1.4 This is now a very basic client. Explaining explicitly what
351     L<AnyEvent::Handle> does or what a I<condvar> is all about is out of scope
352     of this document, please consult L<AnyEvent::Intro> or the manual pages
353     for L<AnyEvent> and L<AnyEvent::Handle>.
354 elmex 1.1
355 root 1.9 =head1 First Steps Into Messaging
356 elmex 1.1
357 root 1.8 To supply the C<send_message> function we now take a look at
358     L<AnyEvent::MP>. This is an example of how it might look like:
359 elmex 1.1
360     ... # the use lines from the above snippet
361    
362     use AnyEvent::MP;
363    
364     sub send_message {
365     my ($msg) = @_;
366    
367     snd $server_port, message => $msg;
368     }
369    
370     ... # the rest of the above script
371    
372 root 1.8 The C<snd> function is exported by L<AnyEvent::MP>, it stands for 'send
373     a message'. The first argument is the I<port> (a I<port> is something
374     that can receive messages, represented by a printable string) of the
375     server which will receive the message. How we get this port will be
376     explained in the next step.
377    
378     The remaining arguments of C<snd> are C<message> and C<$msg>, the first
379     two elements of the I<message> (a I<message> in L<AnyEvent::MP> is a
380     simple list of values, which can be sent to a I<port>).
381    
382     So all the function does is send the two values C<message> (a constant
383     string to tell the server what to expect) and the actual message string.
384    
385     Thats all fine and simple so far, but where do we get the
386     C<$server_port>? Well, we need to get the unique I<port id> of the
387     server's port where it wants to receive all the incoming chat messages. A
388 root 1.9 I<port id> is unfortunately a very unique string, which we are unable to
389     know in advance. But L<AnyEvent::MP> supports the concept of 'registered
390     ports', which is basically a port on the server side registered under
391     a well known name.
392    
393     For example, the server has a port for receiving chat messages with a
394     unique I<port id> and registers it under the name C<chatter>.
395 root 1.4
396 root 1.9 BTW, these "registered port names" should follow similar rules as Perl
397 root 1.4 identifiers, so you should prefix them with your package/module name to
398     make them unique, unless you use them in the main program.
399 elmex 1.1
400 root 1.9 As I<messages> can only be sent to a I<port id> and not just to some name
401     we have to ask the server node for the I<port id> of the port registered
402     as C<chatter>.
403 elmex 1.1
404 root 1.9 =head1 Finding The Chatter Port
405 elmex 1.1
406 root 1.9 Ok, lots of talk, now some code. Now we will actually get the
407     C<$server_port> from the backend:
408 elmex 1.1
409     ...
410    
411     use AnyEvent::MP;
412    
413 root 1.9 my $server_node = "127.0.0.1:1299";
414 elmex 1.1
415 root 1.9 my $client_port = port;
416 elmex 1.1
417 root 1.9 snd $server_node, lookup => "chatter", $client_port, "resolved";
418 elmex 1.1
419 root 1.9 my $resolved_cv = AnyEvent->condvar;
420 elmex 1.1 my $server_port;
421    
422     # setup a receiver callback for the 'resolved' message:
423 root 1.9 rcv $client_port, resolved => sub {
424     my ($tag, $chatter_port_id) = @_;
425 elmex 1.1
426     print "Resolved the server port 'chatter' to $chatter_port_id\n";
427     $server_port = $chatter_port_id;
428    
429     $resolved_cv->send;
430     1
431 root 1.9 };
432 elmex 1.1
433 root 1.9 # lets block the client until we have resolved the server port.
434 elmex 1.1 $resolved_cv->recv;
435    
436     # now setup another receiver callback for the chat messages:
437 root 1.9 rcv $client_port, message => sub {
438     my ($tag, $msg) = @_;
439 elmex 1.1
440     print "chat> $msg\n";
441     0
442 root 1.9 };
443 elmex 1.1
444 root 1.9 # send a 'join' message to the server:
445 elmex 1.1 snd $server_port, join => "$client_port";
446    
447     sub send_message { ...
448    
449 root 1.9 Now that was a lot of new stuff:
450 elmex 1.1
451 root 1.9 First we define the C<$server_node>: In order to refer to another node
452     we need some kind of string to reference it - the node reference. The
453     I<noderef> is basically a comma separated list of C<address:port>
454     pairs. We assume in this tutorial that the server runs on C<127.0.0.1>
455     (localhost) on port 1299, which results in the noderef C<127.0.0.1:1299>.
456    
457     Next, in order to receive a reply from the other node or the server we
458     need to have a I<port> that messages can be sent to. This is what the
459     C<port> function will do for us, it just creates a new local port and
460     returns it's I<port ID> that can then be used to receive messages.
461    
462     When you look carefully, you will see that the first C<snd> uses the
463     C<$server_node> (a noderef) as destination port. Well, what I didn't
464     tell you yet is that each I<node> has a default I<port> to receive
465     messages. The ID of this port is the same as the noderef.
466    
467     This I<default port> provides some special services for us, for example
468     resolving a registered name to a I<port id> (a-ha! finally!).
469    
470     This is exactly what this line does:
471    
472     snd $server_node, lookup => "chatter", $client_port, "resolved";
473    
474     This sends a message with first element being C<lookup>, followed by the
475     (hopefully) registered port name that we want to resolve to a I<port
476     id>: C<chatter>. And in order for the server node to be able to send us
477     back the resolved I<port ID> we have to tell it where to send it: The
478     result message will be sent to C<$client_port> (the I<port id> of the
479     port we just created), and will have the string C<resolved> as the first
480     element.
481    
482     When the node receives this message, it will look up the name, gobble up
483     all the extra arguments we passed, append the resolved name, and send the
484     resulting list as a message.
485 elmex 1.1
486 root 1.9 Next we register a receiver for this C<lookup>-request.
487    
488     rcv $client_port, resolved => sub {
489     my ($tag, $chatter_port_id) = @_;
490     ...
491     1
492     };
493    
494     This sets up a receiver on our own port for messages with the first
495     element being the string C<resolved>. Receivers can match the contents of
496     the messages before actually executing the specified callback.
497    
498     B<Please note> that the every C<rcv> callback has to return either a true
499     or a false value, indicating whether it is B<successful>/B<done> (true) or
500     still wants to B<continue> (false) receiving messages.
501 elmex 1.1
502 root 1.9 In this case we tell the C<$client_port> to look into all the messages
503     it receives and look for the string C<resolved> in the first element of
504     the message. If it is found, the given callback will be called with the
505     message elements as arguments.
506 elmex 1.1
507 root 1.9 Using a string as the first element of the message is called I<tagging>
508     the message. It's common practise to code the 'type' of a message into
509     it's first element, as this allows for simple matching.
510 elmex 1.1
511 root 1.9 The result message will contain the I<port ID> of the well known port
512     C<chatter> as second element, which will be stored in C<$chatter_port_id>.
513 elmex 1.1
514 root 1.9 This port ID will then be stored in C<$server_port>, followed by calling
515     C<send> on $resolved_cv> so the program will continue.
516 elmex 1.1
517 root 1.9 The callback then returns a C<1> (a true value), to indicate that it has
518     done it's job and doesn't want to receive further C<resolved> messages.
519 elmex 1.1
520 root 1.9 After this the chat message receiver callback is registered with the port:
521 elmex 1.1
522 root 1.9 rcv $client_port, message => sub {
523     my ($tag, $msg) = @_;
524 elmex 1.1
525     print "chat> $msg\n";
526 root 1.9
527 elmex 1.1 0
528 root 1.9 };
529 elmex 1.1
530 root 1.9 We assume that all messages that are broadcast to the clients by the
531     server contain the string tag C<message> as first element, and the actual
532     message as second element. The callback returns a false value this time,
533     to indicate that it is not yet done and wants to receive further messages.
534    
535     The last thing to do is to tell the server to send us new chat messages
536     from other clients. We do so by sending the message C<join> followed by
537     our own I<port ID>.
538 elmex 1.1
539     # send the server a 'join' message:
540 root 1.9 snd $server_port, join => $client_port;
541 elmex 1.1
542 root 1.9 This way the server knows where to send all the new messages to.
543 elmex 1.1
544 root 1.8 =head1 The Completed Client
545 elmex 1.1
546     This is the complete client script:
547    
548     #!perl
549 root 1.4
550 elmex 1.1 use AnyEvent;
551     use AnyEvent::Handle;
552     use AnyEvent::MP;
553    
554 root 1.10 my $server_node = "127.0.0.1:1299";
555 elmex 1.1
556 root 1.10 my $client_port = port;
557 elmex 1.1
558 root 1.10 snd $server_node, lookup => "chatter", $client_port, "resolved";
559 elmex 1.1
560 root 1.10 my $resolved_cv = AnyEvent->condvar;
561 elmex 1.1 my $server_port;
562    
563     # setup a receiver callback for the 'resolved' message:
564 root 1.10 rcv $client_port, resolved => sub {
565     my ($tag, $chatter_port_id) = @_;
566 elmex 1.1
567     print "Resolved the server port 'chatter' to $chatter_port_id\n";
568     $server_port = $chatter_port_id;
569    
570     $resolved_cv->send;
571     1
572 root 1.10 };
573 elmex 1.1
574 root 1.10 # lets block the client until we have resolved the server port.
575 elmex 1.1 $resolved_cv->recv;
576    
577     # now setup another receiver callback for the chat messages:
578 root 1.10 rcv $client_port, message => sub {
579     my ($tag, $msg) = @_;
580 elmex 1.1
581     print "chat> $msg\n";
582     0
583 root 1.10 };
584 elmex 1.1
585 root 1.10 # send a 'join' message to the server:
586 elmex 1.1 snd $server_port, join => "$client_port";
587    
588     sub send_message {
589     my ($msg) = @_;
590    
591     snd $server_port, message => $msg;
592     }
593    
594     # make an AnyEvent condition variable for the 'quit' condition
595     # (when we want to exit the client).
596     my $quit_cv = AnyEvent->condvar;
597    
598     my $stdin_hdl = AnyEvent::Handle->new (
599 root 1.10 fh => *STDIN,
600     on_error => sub { $quit_cv->send },
601     on_read => sub {
602 elmex 1.1 my ($hdl) = @_;
603    
604     $hdl->push_read (line => sub {
605     my ($hdl, $line) = @_;
606    
607     if ($line =~ /^\/quit/) { # /quit will end the client
608     $quit_cv->send;
609     } else {
610     send_message ($line);
611     }
612     });
613     }
614     );
615    
616     $quit_cv->recv;
617    
618 root 1.8 =head1 The Server
619 elmex 1.1
620 root 1.10 Ok, we finally come to the server.
621    
622     The server of course also needs to set up a port, and in addition needs to
623     I<register> it, so the clients can find it.
624 elmex 1.1
625 root 1.10 Again, let's jump directly into the code:
626 elmex 1.1
627     #!perl
628 root 1.4
629 elmex 1.1 use AnyEvent;
630     use AnyEvent::MP;
631    
632 root 1.10 become_public "127.0.0.1:1299";
633 elmex 1.1
634 root 1.10 my $chatter_port = port;
635    
636     reg $chatter_port, "chatter";
637 elmex 1.1
638     my %client_ports;
639    
640 root 1.10 rcv $chatter_port,
641     join => sub {
642     my ($tag, $client_port) = @_;
643 elmex 1.1
644 root 1.10 print "got new client port: $client_port\n";
645     $client_ports{$client_port} = 1;
646 elmex 1.5
647 root 1.10 0
648     },
649     message => sub {
650     my ($tag, $msg) = @_;
651 elmex 1.1
652 root 1.10 print "message> $msg\n";
653 elmex 1.1
654 root 1.10 snd $_, message => $msg
655     for keys %client_ports;
656 elmex 1.5
657 root 1.10 0
658 root 1.11 };
659 elmex 1.1
660     AnyEvent->condvar->recv;
661    
662 root 1.10 That is all. Looks much simpler than the client, doesn't it?
663    
664     Let's quickly look over it, as C<rcv> has already been discussed in the
665     client part of this tutorial above.
666 elmex 1.2
667     First this:
668    
669 root 1.10 become_public "127.0.0.1:1299";
670 elmex 1.1
671 root 1.10 This will tell our I<node> to become a I<public> node, which means that it
672     can be contacted via TCP. The first argument should be the I<noderef> the
673     server wants to be reachable at. In this case it's the TCP port 1299 on
674     C<127.0.0.1>.
675    
676     Next we set up two receivers, one for the C<join> messages and another one
677     for the actual messages of type C<messsage>. This is done with a single
678     call to C<rcv>, which allows multiple C<< match => $callback >> pairs.
679    
680     In the C<join> callback we receive the client port, which is simply
681     remembered in the C<%client_ports> hash. In the C<message> callback we
682     just iterate through all known C<%client_ports> and relay the message to
683     them.
684 elmex 1.1
685 root 1.10 That concludes the server.
686 elmex 1.2
687 root 1.8 =head1 The Remaining Problems
688 elmex 1.1
689 root 1.10 The implementation as shown still has some bugs. For instance: How does
690     the server know that the client isn't there anymore, so it can clean up
691     the C<%client_ports> hash? Also, the chat messages have no originator, so
692     we don't know who actually sent the message (which would be quite useful
693 elmex 1.1 for human-to-human interaction: to know who the other one is :).
694    
695 root 1.10 But aside from these issues I hope this tutorial showed you the basics of
696 elmex 1.1 L<AnyEvent::MP> and explained some common idioms.
697    
698 elmex 1.7 How to solve the reliability and C<%client_ports> cleanup problem will
699     be explained later in this tutorial (TODO).
700    
701 root 1.8 =head1 Inside The Protocol
702 elmex 1.7
703     Now, for the interested parties, let me explain some details about the protocol
704     that L<AnyEvent::MP> nodes use to communicate to each other. If you are not
705     interested you can skip this section.
706    
707 root 1.14 Usually TCP is used for communication. Each I<node>, if configured to be
708     a I<public> node with the C<initialise_node> function will listen on the
709     configured TCP port (default is 4040).
710 elmex 1.7
711 root 1.10 If then one I<node> wants to send a message to another I<node> it will
712     connect to the host and port given in the I<port ID>.
713 elmex 1.7
714 root 1.10 Then some handshaking occurs to check whether both I<nodes> know the
715     I<shared secret>. Optionally, TLS can be enabled (about how to do this
716     exactly please consult the L<AnyEvent::MP> man page, just a hint: It
717     should be enough to put the private key and (self signed) certificate in
718     the C<~/.aemp-secret> file of all nodes).
719    
720     After the handshake, messages will be exchanged using a serialiser
721     (usually L<JSON> is used for this, but it is also possible to use other
722     serialization formats such as L<Storable>).
723 elmex 1.7
724 elmex 1.1 =head1 SEE ALSO
725    
726     L<AnyEvent>
727    
728     L<AnyEvent::Handle>
729    
730     L<AnyEvent::MP>
731    
732     =head1 AUTHOR
733    
734     Robin Redeker <elmex@ta-sa.org>
735 root 1.4