1 | =head1 Message Passing for the non-blocked Mind |
1 | =head1 Message Passing for the Non-Blocked Mind |
2 | |
2 | |
3 | =head2 Introduction and Terminology |
3 | =head2 Introduction and Terminology |
4 | |
4 | |
5 | This is a Tutorial about how to get the swing of the new L<AnyEvent::MP> |
5 | This is a tutorial about how to get the swing of the new L<AnyEvent::MP> |
6 | module. Which allows us to transparently pass messages to our own process and |
6 | module. Which allows us to transparently pass messages to our own process and |
7 | to other process on other or the same host. |
7 | to other process on other or the same host. |
8 | |
8 | |
9 | What kind of messages? Well, basically a message here means a list of Perl |
9 | What kind of messages? Well, basically a message here means a list of |
10 | strings, numbers, hashes and arrays, mostly everything that can be expressed as |
10 | Perl strings, numbers, hashes and arrays, mostly everything that can be |
11 | L<JSON> string. |
11 | expressed in a L<JSON> text (as JSON is used by default in the protocol). |
12 | |
12 | |
13 | And next you might ask: between which entities are those messages "passed"? |
13 | And next you might ask: between which entities are those messages being "passed"? |
14 | Basically between C<nodes>, which are basically your applications (as in |
14 | Basically between C<nodes>, which are basically your applications (as in |
15 | processes) that use L<AnyEvent::MP> that run either on the same or different |
15 | processes) that use L<AnyEvent::MP> that run either on the same or different |
16 | hosts. |
16 | hosts. |
17 | |
17 | |
18 | In this Tutorial I'll show you how to write a simple chat server based on |
18 | In this tutorial I'll show you how to write a simple chat server based on |
19 | L<AnyEvent::MP>. |
19 | L<AnyEvent::MP>. |
20 | |
20 | |
21 | =head2 The Chat Client |
21 | =head2 The Chat Client |
22 | |
22 | |
23 | Ok, lets start by implementing the "frontend" of the client. We will delay the |
23 | OK, lets start by implementing the "frontend" of the client. We will delay the |
24 | explanation and the code of the server until we finished the client, as the |
24 | explanation and the code of the server until we finished the client, as the |
25 | most complex things actually happen in the client. |
25 | most complex things actually happen in the client. |
26 | |
26 | |
27 | We will use L<AnyEvent::Handle> to do non-blocking IO read on standard input: |
27 | We will use L<AnyEvent::Handle> to do non-blocking IO read on standard input: |
28 | |
28 | |
… | |
… | |
57 | } |
57 | } |
58 | ); |
58 | ); |
59 | |
59 | |
60 | $quit_cv->recv; |
60 | $quit_cv->recv; |
61 | |
61 | |
62 | This is now a very basic client. Explaining explicitly what L<AnyEvent::Handle> |
62 | This is now a very basic client. Explaining explicitly what |
63 | does or what a I<condvar> is all about is out of scope of this document, please |
63 | L<AnyEvent::Handle> does or what a I<condvar> is all about is out of scope |
64 | consult L<AnyEvent::Intro> or the manpages for L<AnyEvent> and |
64 | of this document, please consult L<AnyEvent::Intro> or the manual pages |
65 | L<AnyEvent::Handle>. |
65 | for L<AnyEvent> and L<AnyEvent::Handle>. |
66 | |
66 | |
67 | =head2 First Step Into Messaging |
67 | =head2 First Step Into Messaging |
68 | |
68 | |
69 | Now we take a look at L<AnyEvent::MP>. We need to know what to do in |
69 | Now we take a look at L<AnyEvent::MP>. We need to know what to do in |
70 | C<send_message>. This is an example how it might look like: |
70 | C<send_message>. This is an example of how it might look like: |
71 | |
71 | |
72 | ... # the use lines from the above snippet |
72 | ... # the use lines from the above snippet |
73 | |
73 | |
74 | use AnyEvent::MP; |
74 | use AnyEvent::MP; |
75 | |
75 | |
… | |
… | |
83 | |
83 | |
84 | The C<snd> function is exported by L<AnyEvent::MP>, it stands for 'send a |
84 | The C<snd> function is exported by L<AnyEvent::MP>, it stands for 'send a |
85 | message'. The first argument is the I<port> (a I<port> is something that can |
85 | message'. The first argument is the I<port> (a I<port> is something that can |
86 | receive messages) of the server which will receive the message . How we get it |
86 | receive messages) of the server which will receive the message . How we get it |
87 | will be explained in the next step. The next arguments of C<snd> are |
87 | will be explained in the next step. The next arguments of C<snd> are |
88 | C<'message'> and C<$msg> are the first two elements of the I<message> (a |
88 | C<message> and C<$msg> are the first two elements of the I<message> (a |
89 | I<message> in L<AnyEvent::MP> is a be a simple list of values, which can be |
89 | I<message> in L<AnyEvent::MP> is a be a simple list of values, which can be |
90 | sent to I<ports>). |
90 | sent to I<ports>). |
91 | |
91 | |
92 | Thats all fine so far, but how do we get the C<$server_port>? Well, we will |
92 | Thats all fine so far, but how do we get the C<$server_port>? Well, we will |
93 | need to get the unique I<port id> of the server's port where he wants to |
93 | need to get the unique I<port id> of the server's port where he wants to |
94 | receive all the incoming chat messages. A I<port id> is unfortunately a very |
94 | receive all the incoming chat messages. A I<port id> is unfortunately a very |
95 | unique string, which we are unable to know in advance. But L<AnyEvent::MP> |
95 | unique string, which we are unable to know in advance. But L<AnyEvent::MP> |
96 | supports the concept of 'well known ports', which is basically a port on the |
96 | supports the concept of 'well known ports', which is basically a port on the |
97 | server side registered under a well known name. For example, the server has a |
97 | server side registered under a well known name. For example, the server has a |
98 | port for receiving chat messages with a unique I<port id> and registered it |
98 | port for receiving chat messages with a unique I<port id> and registered it |
99 | under the name C<"chatter">. |
99 | under the name C<chatter>. |
|
|
100 | |
|
|
101 | BTW, these "well known port names" should follow similar rules as Perl |
|
|
102 | identifiers, so you should prefix them with your package/module name to |
|
|
103 | make them unique, unless you use them in the main program. |
100 | |
104 | |
101 | As I<messages> can only be sent to a I<port id> and not just to a name we have |
105 | As I<messages> can only be sent to a I<port id> and not just to a name we have |
102 | to ask the server I<node> what I<port id> has the well known port with the |
106 | to ask the server I<node> what I<port id> has the well known port with the |
103 | name C<"chatter"> |
107 | name C<chatter>. |
104 | |
108 | |
105 | Another new term, what is a I<node>: The messaging network that can be created with |
109 | Another new term, what is a I<node>: The messaging network that can be created with |
106 | L<AnyEvent::MP> consists of I<nodes>. A I<node> handles all the connection and |
110 | L<AnyEvent::MP> consists of I<nodes>. A I<node> handles all the connection and |
107 | low level message sending logic for it's application. The application in this |
111 | low level message sending logic for its application. The application in this |
108 | case is the server. Also every client has/is a I<node>. |
112 | case is the server. Also every client has/is a I<node>. |
109 | |
113 | |
110 | =head2 Getting The Chatter Port |
114 | =head2 Getting The Chatter Port |
111 | |
115 | |
112 | Ok, lots of talk, now some code. Now we will actually get the C<$server_port> |
116 | Ok, lots of talk, now some code. Now we will actually get the C<$server_port> |
… | |
… | |
161 | |
165 | |
162 | Next thing is the C<$server_node>. In order to refer to another node we need |
166 | Next thing is the C<$server_node>. In order to refer to another node we need |
163 | some kind of string to reference it. The I<noderef> is basically a comma |
167 | some kind of string to reference it. The I<noderef> is basically a comma |
164 | seperated list of C<host:port> pairs. We assume in this tutorial that the |
168 | seperated list of C<host:port> pairs. We assume in this tutorial that the |
165 | server runs on your localhost at port 1299, this gives us the noderef |
169 | server runs on your localhost at port 1299, this gives us the noderef |
166 | C<"localhost:1299">. |
170 | C<localhost:1299>. |
167 | |
171 | |
168 | Now you might ask what the C<"#"> at the end in C<$server_node> the above |
172 | Now you might ask what the C<#> at the end in C<$server_node> the above |
169 | example is about. Well, what I didn't tell you yet is that each I<node> has a |
173 | example is about. Well, what I didn't tell you yet is that each I<node> has a |
170 | default I<port> to receive messages. The default port is the empty string |
174 | default I<port> to receive messages. The default port is the empty string |
171 | C<"">. The I<default port> of a I<node> also provides some special services for |
175 | C<"">. The I<default port> of a I<node> also provides some special services for |
172 | us, for example resolving a well known port to a I<port id>. |
176 | us, for example resolving a well known port to a I<port id>. |
173 | |
177 | |
174 | Now to this line: |
178 | Now to this line: |
175 | |
179 | |
176 | snd $server_node, wkp => "chatter", "$client_port", "resolved"; |
180 | snd $server_node, wkp => "chatter", "$client_port", "resolved"; |
177 | |
181 | |
178 | We send a message with first element being C<'wkp'> (standing for 'well known |
182 | We send a message with first element being C<wkp> (standing for 'well known |
179 | port'). Then the well known port name that we want to resolve to a I<port id>: |
183 | port'). Then the well known port name that we want to resolve to a I<port id>: |
180 | C<"chatter">. And in order for the server node to be able to send us back the |
184 | C<chatter>. And in order for the server node to be able to send us back the |
181 | resolved I<port id> we have to tell it where to send the result message: The |
185 | resolved I<port id> we have to tell it where to send the result message: The |
182 | result message will have as it's first argument the string C<"resolved"> and |
186 | result message will have as it's first argument the string C<resolved> and |
183 | will be sent to C<"$client_port"> (the I<port id> of our own just created |
187 | will be sent to C<$client_port> (the I<port id> of our own just created |
184 | port). |
188 | port). |
185 | |
189 | |
186 | Next this is this: |
190 | Next comes the receiver for this C<wkp> request. |
187 | |
191 | |
188 | $client_port->rcv (resolved => sub { |
192 | $client_port->rcv (resolved => sub { |
189 | my ($client_port, $type, $chatter_port_id) = @_; |
193 | my ($client_port, $type, $chatter_port_id) = @_; |
190 | ... |
194 | ... |
191 | 1 |
195 | 1 |
192 | }); |
196 | }); |
193 | |
197 | |
194 | This sets up a receiver on our own port for the result message with the first |
198 | This sets up a receiver on our own port for the result message with the first |
195 | argument being the string C<"resolved">. Receivers can match the contents of |
199 | argument being the string C<resolved>. Receivers can match the contents of |
196 | the messages before actually 'sending' it to the given callback. |
200 | the messages before actually 'sending' it to the given callback. |
197 | |
201 | |
198 | B<Please note> that the given callback has to return either a true or a false |
202 | B<Please note> that the given callback has to return either a true or a false |
199 | value for indicating whether it is B<done> (true value) or still wants to |
203 | value for indicating whether it is B<done> (true value) or still wants to |
200 | B<continue> (false value) receiving messages. |
204 | B<continue> (false value) receiving messages. |
201 | |
205 | |
202 | In this case we tell the C<$client_port> to look into the received messages and |
206 | In this case we tell the C<$client_port> to look into the received messages and |
203 | look for the string C<"resolved"> in the first element of the message. If it is |
207 | look for the string C<resolved> in the first element of the message. If it is |
204 | found, the given callback will be called with the C<$client_port> as first |
208 | found, the given callback will be called with the C<$client_port> as first |
205 | argument, and the message as the remaining arguments. |
209 | argument, and the message as the remaining arguments. |
206 | |
210 | |
207 | We name the first element of the message C<$type> in this case. It's a common |
211 | We name the first element of the message C<$type> in this case. It's a common |
208 | idiom to code the 'type' of a message into it's first element, this allows for |
212 | idiom to code the 'type' of a message into it's first element, this allows for |
209 | simple matching. |
213 | simple matching. |
210 | |
214 | |
211 | The result message will contain the I<port id> of the well known port C<"chatter"> |
215 | The result message will contain the I<port id> of the well known port C<chatter> |
212 | as next element, and will be put in C<$chatter_port_id>. |
216 | as next element, and will be put in C<$chatter_port_id>. |
213 | |
217 | |
214 | Next we just assign C<$server_port> and return a 1 (a true value) |
218 | Next we just assign C<$server_port> and return a 1 (a true value) |
215 | from the callback. It indicates that we are done and don't want to receive |
219 | from the callback. It indicates that we are done and don't want to receive |
216 | further C<'resolved'> messages with this callback. |
220 | further C<resolved> messages with this callback. |
217 | |
221 | |
218 | Now we continue to the rest of the client by calling C<send> on |
222 | Now we continue to the rest of the client by calling C<send> on |
219 | C<$resolved_cv>. |
223 | C<$resolved_cv>. |
220 | |
224 | |
221 | First new step after this is setting up the chat message receiver callback. |
225 | First new step after this is setting up the chat message receiver callback. |
… | |
… | |
225 | |
229 | |
226 | print "chat> $msg\n"; |
230 | print "chat> $msg\n"; |
227 | 0 |
231 | 0 |
228 | }); |
232 | }); |
229 | |
233 | |
230 | We assume that all messages that are broadcasted to all clients by the server |
234 | We assume that all messages that are broadcast to all clients by the server |
231 | will contain as first element the string C<"message"> and the actual message as |
235 | will contain the string C<message> as first element, and the actual message as |
232 | second element. The callback returns a false value this time, to indicate that |
236 | second element. The callback returns a false value this time, to indicate that |
233 | it wants to continue receiving messages. |
237 | it wants to continue receiving messages. |
234 | |
238 | |
235 | Last but not least we actually tell the server to send us |
239 | Last but not least we actually tell the server to send us |
236 | the new chat messages from other clients. We do so by sending the |
240 | the new chat messages from other clients. We do so by sending the |
237 | message type C<'join'> followed by our own I<port id>. |
241 | message type C<join> followed by our own I<port id>. |
238 | |
242 | |
239 | # send the server a 'join' message: |
243 | # send the server a 'join' message: |
240 | snd $server_port, join => "$client_port"; |
244 | snd $server_port, join => "$client_port"; |
241 | |
245 | |
242 | Then the server knows where to send all the new messages to. |
246 | Then the server knows where to send all the new messages to. |
… | |
… | |
244 | =head2 The Finished Client |
248 | =head2 The Finished Client |
245 | |
249 | |
246 | This is the complete client script: |
250 | This is the complete client script: |
247 | |
251 | |
248 | #!perl |
252 | #!perl |
|
|
253 | |
249 | use AnyEvent; |
254 | use AnyEvent; |
250 | use AnyEvent::Handle; |
255 | use AnyEvent::Handle; |
251 | use AnyEvent::MP; |
256 | use AnyEvent::MP; |
252 | |
257 | |
253 | my $resolved_cv = AnyEvent->condvar; |
258 | my $resolved_cv = AnyEvent->condvar; |
… | |
… | |
316 | $quit_cv->recv; |
321 | $quit_cv->recv; |
317 | |
322 | |
318 | =head2 The Server |
323 | =head2 The Server |
319 | |
324 | |
320 | Ok, now finally to the server. What do we need? Well, we need to setup |
325 | Ok, now finally to the server. What do we need? Well, we need to setup |
321 | the well known port C<"chatter"> where all clients send their messages to. |
326 | the well known port C<chatter> where all clients send their messages to. |
322 | |
327 | |
323 | Up and into code right now: |
328 | Up and into code right now: |
324 | |
329 | |
325 | #!perl |
330 | #!perl |
|
|
331 | |
326 | use AnyEvent; |
332 | use AnyEvent; |
327 | use AnyEvent::MP; |
333 | use AnyEvent::MP; |
328 | |
334 | |
329 | become_public "localhost:1299"; |
335 | become_public "localhost:1299"; |
330 | |
336 | |
… | |
… | |
390 | L<AnyEvent::MP> |
396 | L<AnyEvent::MP> |
391 | |
397 | |
392 | =head1 AUTHOR |
398 | =head1 AUTHOR |
393 | |
399 | |
394 | Robin Redeker <elmex@ta-sa.org> |
400 | Robin Redeker <elmex@ta-sa.org> |
|
|
401 | |