… | |
… | |
13 | And next you might ask: between which entities are those messages being |
13 | And next you might ask: between which entities are those messages being |
14 | "passed"? Physically within or between I<nodes>: a nodes is basically a |
14 | "passed"? Physically within or between I<nodes>: a nodes is basically a |
15 | process/program that use L<AnyEvent::MP> and can run either on the same or |
15 | process/program that use L<AnyEvent::MP> and can run either on the same or |
16 | different hosts. |
16 | different hosts. |
17 | |
17 | |
18 | To make this more managable, every node can contain any number of |
18 | To make this more manageable, every node can contain any number of |
19 | I<ports>: Ports are ultimately the receivers of your messages. |
19 | I<ports>: Ports are ultimately the receivers of your messages. |
20 | |
20 | |
21 | In this tutorial I'll show you how to write a simple chat server based |
21 | In this tutorial I'll show you how to write a simple chat server based on |
22 | on L<AnyEvent::MP>. This example is used because it nicely shows how to |
22 | L<AnyEvent::MP>. This example is used because it nicely shows how to organise a |
23 | organise a simple application, but keep in mind that every node trusts any |
23 | simple application, but keep in mind that every node trusts any other, so this |
24 | other, so this chat cannot be used to implement a real chat server and |
24 | chat cannot be used to implement a real public chat server and client system, |
25 | client system, but it can be used to implement a distributed chat server |
25 | but it can be used to implement a distributed chat server for example. |
26 | for example. |
|
|
27 | |
26 | |
28 | =head1 System Requirements and System Setup |
27 | =head1 System Requirements and System Setup |
29 | |
28 | |
30 | Before we can start we have to make sure some things work on your |
29 | Before we can start we have to make sure some things work on your |
31 | system. |
30 | system. |
… | |
… | |
33 | You should of course first make sure that L<AnyEvent> and L<AnyEvent::MP> |
32 | You should of course first make sure that L<AnyEvent> and L<AnyEvent::MP> |
34 | are installed. But how to do that is out of scope of this tutorial. |
33 | are installed. But how to do that is out of scope of this tutorial. |
35 | |
34 | |
36 | Then we have to setup a I<shared secret>: for two L<AnyEvent::MP> nodes to |
35 | Then we have to setup a I<shared secret>: for two L<AnyEvent::MP> nodes to |
37 | be able to communicate with each other and authenticate each other it is |
36 | be able to communicate with each other and authenticate each other it is |
38 | necessary to setup the same I<shared secret> for both of them (use use TLS |
37 | necessary to setup the same I<shared secret> for both of them (or use TLS |
39 | certificates). |
38 | certificates). |
40 | |
39 | |
41 | The easiest way is to set this up is to use the F<aemp> utility: |
40 | The easiest way is to set this up is to use the F<aemp> utility: |
42 | |
41 | |
43 | aemp gensecret |
42 | aemp gensecret |
… | |
… | |
52 | Connections will only be successful when the nodes that want to connect to |
51 | Connections will only be successful when the nodes that want to connect to |
53 | each other have the same I<shared secret> (or successfully verify the TLS |
52 | each other have the same I<shared secret> (or successfully verify the TLS |
54 | certificate of the other side). |
53 | certificate of the other side). |
55 | |
54 | |
56 | B<If something does not work as expected, and for example tcpdump shows |
55 | B<If something does not work as expected, and for example tcpdump shows |
57 | that the connections are closed almost immediatly, you should make sure |
56 | that the connections are closed almost immediately, you should make sure |
58 | that F<~/.perl-anyevent-mp> is the same on all hosts/user accounts that |
57 | that F<~/.perl-anyevent-mp> is the same on all hosts/user accounts that |
59 | you try to connect with each other!> |
58 | you try to connect with each other!> |
|
|
59 | |
|
|
60 | =head1 Passing Your First Message |
|
|
61 | |
|
|
62 | As start lets have a look at the messaging API. The next example is just a |
|
|
63 | demo to show the basic elements of message passing with L<AnyEvent::MP>. |
|
|
64 | It shout just print: "Ending with: 123". So here the code: |
|
|
65 | |
|
|
66 | use AnyEvent; |
|
|
67 | use AnyEvent::MP; |
|
|
68 | |
|
|
69 | initialise_node; |
|
|
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 | It already contains lots of the API that we are going to use. First there |
|
|
85 | is C<initialise_node>, which will initialise the L<AnyEvent::MP> node for that |
|
|
86 | process. |
|
|
87 | |
|
|
88 | Next there is the C<port> function which will create a I<port id> for us, where |
|
|
89 | we can wait for messages and send messages to. The port id is a simple string, |
|
|
90 | which acts as identifier for a port, with the form C<noderef#portname>. The |
|
|
91 | I<noderef> is basically a string that refers to the node and also contains |
|
|
92 | enough information to contact the node from the outside. The I<portname> is |
|
|
93 | usually just a random string. |
|
|
94 | |
|
|
95 | Next the call to C<rcv> sets up a receiver callback. The first element in |
|
|
96 | every message is usually denoting it's I<type> or I<tag>. Which should be a |
|
|
97 | simple string, the second argument to C<rcv> lets us match the tag of a |
|
|
98 | message. If it matches, the callback will be called, with the remaining |
|
|
99 | elements of the message as arguments. |
|
|
100 | |
|
|
101 | C<snd> sends a message. The message consists of two elements: The string |
|
|
102 | C<'test'> and the number C<123>. |
|
|
103 | |
|
|
104 | The message arrives in the callback we setup with C<rcv> and will trigger the |
|
|
105 | condition variable C<$end_cv> to deliver the result value and end the program. |
60 | |
106 | |
61 | =head1 The Chat Client |
107 | =head1 The Chat Client |
62 | |
108 | |
63 | OK, lets start by implementing the "frontend" of the client. We will |
109 | OK, lets start by implementing the "frontend" of the client. We will |
64 | develop the client first and postpone the server for later, as the most |
110 | develop the client first and postpone the server for later, as the most |