ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/AnyEvent-MP/MP/Intro.pod
Revision: 1.18
Committed: Fri Aug 28 14:43:53 2009 UTC (14 years, 9 months ago) by elmex
Branch: MAIN
Changes since 1.17: +107 -6 lines
Log Message:
more work on the intro.

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 root 1.8 =head1 The Chat Client
254    
255     OK, lets start by implementing the "frontend" of the client. We will
256     develop the client first and postpone the server for later, as the most
257     complex things actually happen in the client.
258    
259     We will use L<AnyEvent::Handle> to do non-blocking IO read on standard
260     input (all of this code deals with actually handling user input, no
261     message passing yet):
262 elmex 1.7
263 root 1.8 #!perl
264 elmex 1.1
265     use AnyEvent;
266     use AnyEvent::Handle;
267    
268     sub send_message {
269     die "This is where we will send the messages to the server"
270     . "in the next step of this tutorial.\n"
271     }
272    
273     # make an AnyEvent condition variable for the 'quit' condition
274     # (when we want to exit the client).
275     my $quit_cv = AnyEvent->condvar;
276    
277     my $stdin_hdl = AnyEvent::Handle->new (
278 root 1.8 fh => *STDIN,
279     on_error => sub { $quit_cv->send },
280     on_read => sub {
281 elmex 1.1 my ($hdl) = @_;
282    
283     $hdl->push_read (line => sub {
284     my ($hdl, $line) = @_;
285    
286     if ($line =~ /^\/quit/) { # /quit will end the client
287     $quit_cv->send;
288     } else {
289     send_message ($line);
290     }
291     });
292     }
293     );
294    
295     $quit_cv->recv;
296    
297 root 1.4 This is now a very basic client. Explaining explicitly what
298     L<AnyEvent::Handle> does or what a I<condvar> is all about is out of scope
299     of this document, please consult L<AnyEvent::Intro> or the manual pages
300     for L<AnyEvent> and L<AnyEvent::Handle>.
301 elmex 1.1
302 root 1.9 =head1 First Steps Into Messaging
303 elmex 1.1
304 root 1.8 To supply the C<send_message> function we now take a look at
305     L<AnyEvent::MP>. This is an example of how it might look like:
306 elmex 1.1
307     ... # the use lines from the above snippet
308    
309     use AnyEvent::MP;
310    
311     sub send_message {
312     my ($msg) = @_;
313    
314     snd $server_port, message => $msg;
315     }
316    
317     ... # the rest of the above script
318    
319 root 1.8 The C<snd> function is exported by L<AnyEvent::MP>, it stands for 'send
320     a message'. The first argument is the I<port> (a I<port> is something
321     that can receive messages, represented by a printable string) of the
322     server which will receive the message. How we get this port will be
323     explained in the next step.
324    
325     The remaining arguments of C<snd> are C<message> and C<$msg>, the first
326     two elements of the I<message> (a I<message> in L<AnyEvent::MP> is a
327     simple list of values, which can be sent to a I<port>).
328    
329     So all the function does is send the two values C<message> (a constant
330     string to tell the server what to expect) and the actual message string.
331    
332     Thats all fine and simple so far, but where do we get the
333     C<$server_port>? Well, we need to get the unique I<port id> of the
334     server's port where it wants to receive all the incoming chat messages. A
335 root 1.9 I<port id> is unfortunately a very unique string, which we are unable to
336     know in advance. But L<AnyEvent::MP> supports the concept of 'registered
337     ports', which is basically a port on the server side registered under
338     a well known name.
339    
340     For example, the server has a port for receiving chat messages with a
341     unique I<port id> and registers it under the name C<chatter>.
342 root 1.4
343 root 1.9 BTW, these "registered port names" should follow similar rules as Perl
344 root 1.4 identifiers, so you should prefix them with your package/module name to
345     make them unique, unless you use them in the main program.
346 elmex 1.1
347 root 1.9 As I<messages> can only be sent to a I<port id> and not just to some name
348     we have to ask the server node for the I<port id> of the port registered
349     as C<chatter>.
350 elmex 1.1
351 root 1.9 =head1 Finding The Chatter Port
352 elmex 1.1
353 root 1.9 Ok, lots of talk, now some code. Now we will actually get the
354     C<$server_port> from the backend:
355 elmex 1.1
356     ...
357    
358     use AnyEvent::MP;
359    
360 root 1.9 my $server_node = "127.0.0.1:1299";
361 elmex 1.1
362 root 1.9 my $client_port = port;
363 elmex 1.1
364 root 1.9 snd $server_node, lookup => "chatter", $client_port, "resolved";
365 elmex 1.1
366 root 1.9 my $resolved_cv = AnyEvent->condvar;
367 elmex 1.1 my $server_port;
368    
369     # setup a receiver callback for the 'resolved' message:
370 root 1.9 rcv $client_port, resolved => sub {
371     my ($tag, $chatter_port_id) = @_;
372 elmex 1.1
373     print "Resolved the server port 'chatter' to $chatter_port_id\n";
374     $server_port = $chatter_port_id;
375    
376     $resolved_cv->send;
377     1
378 root 1.9 };
379 elmex 1.1
380 root 1.9 # lets block the client until we have resolved the server port.
381 elmex 1.1 $resolved_cv->recv;
382    
383     # now setup another receiver callback for the chat messages:
384 root 1.9 rcv $client_port, message => sub {
385     my ($tag, $msg) = @_;
386 elmex 1.1
387     print "chat> $msg\n";
388     0
389 root 1.9 };
390 elmex 1.1
391 root 1.9 # send a 'join' message to the server:
392 elmex 1.1 snd $server_port, join => "$client_port";
393    
394     sub send_message { ...
395    
396 root 1.9 Now that was a lot of new stuff:
397 elmex 1.1
398 root 1.9 First we define the C<$server_node>: In order to refer to another node
399     we need some kind of string to reference it - the node reference. The
400     I<noderef> is basically a comma separated list of C<address:port>
401     pairs. We assume in this tutorial that the server runs on C<127.0.0.1>
402     (localhost) on port 1299, which results in the noderef C<127.0.0.1:1299>.
403    
404     Next, in order to receive a reply from the other node or the server we
405     need to have a I<port> that messages can be sent to. This is what the
406     C<port> function will do for us, it just creates a new local port and
407     returns it's I<port ID> that can then be used to receive messages.
408    
409     When you look carefully, you will see that the first C<snd> uses the
410     C<$server_node> (a noderef) as destination port. Well, what I didn't
411     tell you yet is that each I<node> has a default I<port> to receive
412     messages. The ID of this port is the same as the noderef.
413    
414     This I<default port> provides some special services for us, for example
415     resolving a registered name to a I<port id> (a-ha! finally!).
416    
417     This is exactly what this line does:
418    
419     snd $server_node, lookup => "chatter", $client_port, "resolved";
420    
421     This sends a message with first element being C<lookup>, followed by the
422     (hopefully) registered port name that we want to resolve to a I<port
423     id>: C<chatter>. And in order for the server node to be able to send us
424     back the resolved I<port ID> we have to tell it where to send it: The
425     result message will be sent to C<$client_port> (the I<port id> of the
426     port we just created), and will have the string C<resolved> as the first
427     element.
428    
429     When the node receives this message, it will look up the name, gobble up
430     all the extra arguments we passed, append the resolved name, and send the
431     resulting list as a message.
432 elmex 1.1
433 root 1.9 Next we register a receiver for this C<lookup>-request.
434    
435     rcv $client_port, resolved => sub {
436     my ($tag, $chatter_port_id) = @_;
437     ...
438     1
439     };
440    
441     This sets up a receiver on our own port for messages with the first
442     element being the string C<resolved>. Receivers can match the contents of
443     the messages before actually executing the specified callback.
444    
445     B<Please note> that the every C<rcv> callback has to return either a true
446     or a false value, indicating whether it is B<successful>/B<done> (true) or
447     still wants to B<continue> (false) receiving messages.
448 elmex 1.1
449 root 1.9 In this case we tell the C<$client_port> to look into all the messages
450     it receives and look for the string C<resolved> in the first element of
451     the message. If it is found, the given callback will be called with the
452     message elements as arguments.
453 elmex 1.1
454 root 1.9 Using a string as the first element of the message is called I<tagging>
455     the message. It's common practise to code the 'type' of a message into
456     it's first element, as this allows for simple matching.
457 elmex 1.1
458 root 1.9 The result message will contain the I<port ID> of the well known port
459     C<chatter> as second element, which will be stored in C<$chatter_port_id>.
460 elmex 1.1
461 root 1.9 This port ID will then be stored in C<$server_port>, followed by calling
462     C<send> on $resolved_cv> so the program will continue.
463 elmex 1.1
464 root 1.9 The callback then returns a C<1> (a true value), to indicate that it has
465     done it's job and doesn't want to receive further C<resolved> messages.
466 elmex 1.1
467 root 1.9 After this the chat message receiver callback is registered with the port:
468 elmex 1.1
469 root 1.9 rcv $client_port, message => sub {
470     my ($tag, $msg) = @_;
471 elmex 1.1
472     print "chat> $msg\n";
473 root 1.9
474 elmex 1.1 0
475 root 1.9 };
476 elmex 1.1
477 root 1.9 We assume that all messages that are broadcast to the clients by the
478     server contain the string tag C<message> as first element, and the actual
479     message as second element. The callback returns a false value this time,
480     to indicate that it is not yet done and wants to receive further messages.
481    
482     The last thing to do is to tell the server to send us new chat messages
483     from other clients. We do so by sending the message C<join> followed by
484     our own I<port ID>.
485 elmex 1.1
486     # send the server a 'join' message:
487 root 1.9 snd $server_port, join => $client_port;
488 elmex 1.1
489 root 1.9 This way the server knows where to send all the new messages to.
490 elmex 1.1
491 root 1.8 =head1 The Completed Client
492 elmex 1.1
493     This is the complete client script:
494    
495     #!perl
496 root 1.4
497 elmex 1.1 use AnyEvent;
498     use AnyEvent::Handle;
499     use AnyEvent::MP;
500    
501 root 1.10 my $server_node = "127.0.0.1:1299";
502 elmex 1.1
503 root 1.10 my $client_port = port;
504 elmex 1.1
505 root 1.10 snd $server_node, lookup => "chatter", $client_port, "resolved";
506 elmex 1.1
507 root 1.10 my $resolved_cv = AnyEvent->condvar;
508 elmex 1.1 my $server_port;
509    
510     # setup a receiver callback for the 'resolved' message:
511 root 1.10 rcv $client_port, resolved => sub {
512     my ($tag, $chatter_port_id) = @_;
513 elmex 1.1
514     print "Resolved the server port 'chatter' to $chatter_port_id\n";
515     $server_port = $chatter_port_id;
516    
517     $resolved_cv->send;
518     1
519 root 1.10 };
520 elmex 1.1
521 root 1.10 # lets block the client until we have resolved the server port.
522 elmex 1.1 $resolved_cv->recv;
523    
524     # now setup another receiver callback for the chat messages:
525 root 1.10 rcv $client_port, message => sub {
526     my ($tag, $msg) = @_;
527 elmex 1.1
528     print "chat> $msg\n";
529     0
530 root 1.10 };
531 elmex 1.1
532 root 1.10 # send a 'join' message to the server:
533 elmex 1.1 snd $server_port, join => "$client_port";
534    
535     sub send_message {
536     my ($msg) = @_;
537    
538     snd $server_port, message => $msg;
539     }
540    
541     # make an AnyEvent condition variable for the 'quit' condition
542     # (when we want to exit the client).
543     my $quit_cv = AnyEvent->condvar;
544    
545     my $stdin_hdl = AnyEvent::Handle->new (
546 root 1.10 fh => *STDIN,
547     on_error => sub { $quit_cv->send },
548     on_read => sub {
549 elmex 1.1 my ($hdl) = @_;
550    
551     $hdl->push_read (line => sub {
552     my ($hdl, $line) = @_;
553    
554     if ($line =~ /^\/quit/) { # /quit will end the client
555     $quit_cv->send;
556     } else {
557     send_message ($line);
558     }
559     });
560     }
561     );
562    
563     $quit_cv->recv;
564    
565 root 1.8 =head1 The Server
566 elmex 1.1
567 root 1.10 Ok, we finally come to the server.
568    
569     The server of course also needs to set up a port, and in addition needs to
570     I<register> it, so the clients can find it.
571 elmex 1.1
572 root 1.10 Again, let's jump directly into the code:
573 elmex 1.1
574     #!perl
575 root 1.4
576 elmex 1.1 use AnyEvent;
577     use AnyEvent::MP;
578    
579 root 1.10 become_public "127.0.0.1:1299";
580 elmex 1.1
581 root 1.10 my $chatter_port = port;
582    
583     reg $chatter_port, "chatter";
584 elmex 1.1
585     my %client_ports;
586    
587 root 1.10 rcv $chatter_port,
588     join => sub {
589     my ($tag, $client_port) = @_;
590 elmex 1.1
591 root 1.10 print "got new client port: $client_port\n";
592     $client_ports{$client_port} = 1;
593 elmex 1.5
594 root 1.10 0
595     },
596     message => sub {
597     my ($tag, $msg) = @_;
598 elmex 1.1
599 root 1.10 print "message> $msg\n";
600 elmex 1.1
601 root 1.10 snd $_, message => $msg
602     for keys %client_ports;
603 elmex 1.5
604 root 1.10 0
605 root 1.11 };
606 elmex 1.1
607     AnyEvent->condvar->recv;
608    
609 root 1.10 That is all. Looks much simpler than the client, doesn't it?
610    
611     Let's quickly look over it, as C<rcv> has already been discussed in the
612     client part of this tutorial above.
613 elmex 1.2
614     First this:
615    
616 root 1.10 become_public "127.0.0.1:1299";
617 elmex 1.1
618 root 1.10 This will tell our I<node> to become a I<public> node, which means that it
619     can be contacted via TCP. The first argument should be the I<noderef> the
620     server wants to be reachable at. In this case it's the TCP port 1299 on
621     C<127.0.0.1>.
622    
623     Next we set up two receivers, one for the C<join> messages and another one
624     for the actual messages of type C<messsage>. This is done with a single
625     call to C<rcv>, which allows multiple C<< match => $callback >> pairs.
626    
627     In the C<join> callback we receive the client port, which is simply
628     remembered in the C<%client_ports> hash. In the C<message> callback we
629     just iterate through all known C<%client_ports> and relay the message to
630     them.
631 elmex 1.1
632 root 1.10 That concludes the server.
633 elmex 1.2
634 root 1.8 =head1 The Remaining Problems
635 elmex 1.1
636 root 1.10 The implementation as shown still has some bugs. For instance: How does
637     the server know that the client isn't there anymore, so it can clean up
638     the C<%client_ports> hash? Also, the chat messages have no originator, so
639     we don't know who actually sent the message (which would be quite useful
640 elmex 1.1 for human-to-human interaction: to know who the other one is :).
641    
642 root 1.10 But aside from these issues I hope this tutorial showed you the basics of
643 elmex 1.1 L<AnyEvent::MP> and explained some common idioms.
644    
645 elmex 1.7 How to solve the reliability and C<%client_ports> cleanup problem will
646     be explained later in this tutorial (TODO).
647    
648 root 1.8 =head1 Inside The Protocol
649 elmex 1.7
650     Now, for the interested parties, let me explain some details about the protocol
651     that L<AnyEvent::MP> nodes use to communicate to each other. If you are not
652     interested you can skip this section.
653    
654 root 1.14 Usually TCP is used for communication. Each I<node>, if configured to be
655     a I<public> node with the C<initialise_node> function will listen on the
656     configured TCP port (default is 4040).
657 elmex 1.7
658 root 1.10 If then one I<node> wants to send a message to another I<node> it will
659     connect to the host and port given in the I<port ID>.
660 elmex 1.7
661 root 1.10 Then some handshaking occurs to check whether both I<nodes> know the
662     I<shared secret>. Optionally, TLS can be enabled (about how to do this
663     exactly please consult the L<AnyEvent::MP> man page, just a hint: It
664     should be enough to put the private key and (self signed) certificate in
665     the C<~/.aemp-secret> file of all nodes).
666    
667     After the handshake, messages will be exchanged using a serialiser
668     (usually L<JSON> is used for this, but it is also possible to use other
669     serialization formats such as L<Storable>).
670 elmex 1.7
671 elmex 1.1 =head1 SEE ALSO
672    
673     L<AnyEvent>
674    
675     L<AnyEvent::Handle>
676    
677     L<AnyEvent::MP>
678    
679     =head1 AUTHOR
680    
681     Robin Redeker <elmex@ta-sa.org>
682 root 1.4