ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/AnyEvent-MP/MP/Intro.pod
(Generate patch)

Comparing AnyEvent-MP/MP/Intro.pod (file contents):
Revision 1.8 by root, Tue Aug 4 20:00:00 2009 UTC vs.
Revision 1.9 by root, Tue Aug 4 20:47:39 2009 UTC

9What kind of messages? Well, basically a message here means a list of 9What kind of messages? Well, basically a message here means a list of
10Perl strings, numbers, hashes and arrays, mostly everything that can be 10Perl strings, numbers, hashes and arrays, mostly everything that can be
11expressed as a L<JSON> text (as JSON is used by default in the protocol). 11expressed as a L<JSON> text (as JSON is used by default in the protocol).
12 12
13And next you might ask: between which entities are those messages 13And next you might ask: between which entities are those messages
14being "passed"? Basically between C<nodes>: a nodes is basically a 14being "passed"? Effectively between I<nodes>: a nodes is basically a
15process/program that use L<AnyEvent::MP> and can run either on the same or 15process/program that use L<AnyEvent::MP> and can run either on the same or
16different hosts. 16different hosts.
17
18To make this more managable, every node can contain any number of
19I<ports>: Ports are ultimately the receivers of your messages.
17 20
18In this tutorial I'll show you how to write a simple chat server based on 21In this tutorial I'll show you how to write a simple chat server based on
19L<AnyEvent::MP>. 22L<AnyEvent::MP>.
20 23
21=head1 System Requirements 24=head1 System Requirements
94This is now a very basic client. Explaining explicitly what 97This is now a very basic client. Explaining explicitly what
95L<AnyEvent::Handle> does or what a I<condvar> is all about is out of scope 98L<AnyEvent::Handle> does or what a I<condvar> is all about is out of scope
96of this document, please consult L<AnyEvent::Intro> or the manual pages 99of this document, please consult L<AnyEvent::Intro> or the manual pages
97for L<AnyEvent> and L<AnyEvent::Handle>. 100for L<AnyEvent> and L<AnyEvent::Handle>.
98 101
99=head1 First Step Into Messaging 102=head1 First Steps Into Messaging
100 103
101To supply the C<send_message> function we now take a look at 104To supply the C<send_message> function we now take a look at
102L<AnyEvent::MP>. This is an example of how it might look like: 105L<AnyEvent::MP>. This is an example of how it might look like:
103 106
104 ... # the use lines from the above snippet 107 ... # the use lines from the above snippet
127string to tell the server what to expect) and the actual message string. 130string to tell the server what to expect) and the actual message string.
128 131
129Thats all fine and simple so far, but where do we get the 132Thats all fine and simple so far, but where do we get the
130C<$server_port>? Well, we need to get the unique I<port id> of the 133C<$server_port>? Well, we need to get the unique I<port id> of the
131server's port where it wants to receive all the incoming chat messages. A 134server's port where it wants to receive all the incoming chat messages. A
132I<port id> is unfortunately a very unique string, which we are unable 135I<port id> is unfortunately a very unique string, which we are unable to
133to know in advance. But L<AnyEvent::MP> supports the concept of 'well 136know in advance. But L<AnyEvent::MP> supports the concept of 'registered
134known ports', which is basically a port on the server side registered 137ports', which is basically a port on the server side registered under
135under a well known name. For example, the server has a port for receiving 138a well known name.
136chat messages with a unique I<port id> and registered it under the name
137C<chatter>.
138 139
140For example, the server has a port for receiving chat messages with a
141unique I<port id> and registers it under the name C<chatter>.
142
139BTW, these "well known port names" should follow similar rules as Perl 143BTW, these "registered port names" should follow similar rules as Perl
140identifiers, so you should prefix them with your package/module name to 144identifiers, so you should prefix them with your package/module name to
141make them unique, unless you use them in the main program. 145make them unique, unless you use them in the main program.
142 146
143As I<messages> can only be sent to a I<port id> and not just to a name we have 147As I<messages> can only be sent to a I<port id> and not just to some name
144to ask the server I<node> what I<port id> has the well known port with the 148we have to ask the server node for the I<port id> of the port registered
145name C<chatter>. 149as C<chatter>.
146 150
147Another new term, what is a I<node>: The messaging network that can be created with
148L<AnyEvent::MP> consists of I<nodes>. A I<node> handles all the connection and
149low level message sending logic for its application. The application in this
150case is the server. Also every client has/is a I<node>.
151
152=head1 Getting The Chatter Port 151=head1 Finding The Chatter Port
153 152
154Ok, lots of talk, now some code. Now we will actually get the C<$server_port> 153Ok, lots of talk, now some code. Now we will actually get the
155from the backend: 154C<$server_port> from the backend:
156 155
157 ... 156 ...
158 157
159 use AnyEvent::MP; 158 use AnyEvent::MP;
160 159
160 my $server_node = "127.0.0.1:1299";
161
162 my $client_port = port;
163
164 snd $server_node, lookup => "chatter", $client_port, "resolved";
165
161 my $resolved_cv = AnyEvent->condvar; 166 my $resolved_cv = AnyEvent->condvar;
162
163 my $client_port = create_port;
164
165 my $server_node = "localhost:1299#";
166
167 snd $server_node, wkp => "chatter", "$client_port", "resolved";
168
169 my $server_port; 167 my $server_port;
170 168
171 # setup a receiver callback for the 'resolved' message: 169 # setup a receiver callback for the 'resolved' message:
172 $client_port->rcv (resolved => sub { 170 rcv $client_port, resolved => sub {
173 my ($client_port, $type, $chatter_port_id) = @_; 171 my ($tag, $chatter_port_id) = @_;
174 172
175 print "Resolved the server port 'chatter' to $chatter_port_id\n"; 173 print "Resolved the server port 'chatter' to $chatter_port_id\n";
176 $server_port = $chatter_port_id; 174 $server_port = $chatter_port_id;
177 175
178 $resolved_cv->send; 176 $resolved_cv->send;
179 1 177 1
180 }); 178 };
181 179
182 # lets block the client until we resolved the server port. 180 # lets block the client until we have resolved the server port.
183 $resolved_cv->recv; 181 $resolved_cv->recv;
184 182
185 # now setup another receiver callback for the chat messages: 183 # now setup another receiver callback for the chat messages:
186 $client_port->rcv (message => sub { 184 rcv $client_port, message => sub {
187 my ($client_port, $type, $msg) = @_; 185 my ($tag, $msg) = @_;
188 186
189 print "chat> $msg\n"; 187 print "chat> $msg\n";
190 0 188 0
191 }); 189 };
192 190
193 # send the server a 'join' message: 191 # send a 'join' message to the server:
194 snd $server_port, join => "$client_port"; 192 snd $server_port, join => "$client_port";
195 193
196 sub send_message { ... 194 sub send_message { ...
197 195
198Now that was a lot of new stuff. In order to ask the server and receive an 196Now that was a lot of new stuff:
199answer we need to have a I<port> where we can receive the answer.
200This is what C<create_port> will do for us, it just creates a new local
201port and returns us an object (that will btw. stringify to the I<port id>),
202that we can use to receive messages.
203 197
204Next thing is the C<$server_node>. In order to refer to another node we need 198First we define the C<$server_node>: In order to refer to another node
205some kind of string to reference it. The I<noderef> is basically a comma 199we need some kind of string to reference it - the node reference. The
206separated list of C<host:port> pairs. We assume in this tutorial that the 200I<noderef> is basically a comma separated list of C<address:port>
207server runs on your localhost at port 1299, this gives us the noderef 201pairs. We assume in this tutorial that the server runs on C<127.0.0.1>
208C<localhost:1299>. 202(localhost) on port 1299, which results in the noderef C<127.0.0.1:1299>.
209 203
210Now you might ask what the C<#> at the end in C<$server_node> the above 204Next, in order to receive a reply from the other node or the server we
211example is about. Well, what I didn't tell you yet is that each I<node> has a 205need to have a I<port> that messages can be sent to. This is what the
212default I<port> to receive messages. The default port is the empty string 206C<port> function will do for us, it just creates a new local port and
213C<"">. The I<default port> of a I<node> also provides some special services for 207returns it's I<port ID> that can then be used to receive messages.
214us, for example resolving a well known port to a I<port id>.
215 208
216Now to this line: 209When you look carefully, you will see that the first C<snd> uses the
210C<$server_node> (a noderef) as destination port. Well, what I didn't
211tell you yet is that each I<node> has a default I<port> to receive
212messages. The ID of this port is the same as the noderef.
217 213
214This I<default port> provides some special services for us, for example
215resolving a registered name to a I<port id> (a-ha! finally!).
216
217This is exactly what this line does:
218
218 snd $server_node, wkp => "chatter", "$client_port", "resolved"; 219 snd $server_node, lookup => "chatter", $client_port, "resolved";
219 220
220We send a message with first element being C<wkp> (standing for 'well known 221This sends a message with first element being C<lookup>, followed by the
221port'). Then the well known port name that we want to resolve to a I<port id>: 222(hopefully) registered port name that we want to resolve to a I<port
222C<chatter>. And in order for the server node to be able to send us back the 223id>: C<chatter>. And in order for the server node to be able to send us
223resolved I<port id> we have to tell it where to send the result message: The 224back the resolved I<port ID> we have to tell it where to send it: The
224result message will have as it's first argument the string C<resolved> and
225will be sent to C<$client_port> (the I<port id> of our own just created 225result message will be sent to C<$client_port> (the I<port id> of the
226port). 226port we just created), and will have the string C<resolved> as the first
227element.
227 228
229When the node receives this message, it will look up the name, gobble up
230all the extra arguments we passed, append the resolved name, and send the
231resulting list as a message.
232
228Next comes the receiver for this C<wkp> request. 233Next we register a receiver for this C<lookup>-request.
229 234
230 $client_port->rcv (resolved => sub { 235 rcv $client_port, resolved => sub {
231 my ($client_port, $type, $chatter_port_id) = @_; 236 my ($tag, $chatter_port_id) = @_;
232 ... 237 ...
233 1 238 1
234 }); 239 };
235 240
236This sets up a receiver on our own port for the result message with the first 241This sets up a receiver on our own port for messages with the first
237argument being the string C<resolved>. Receivers can match the contents of 242element being the string C<resolved>. Receivers can match the contents of
238the messages before actually 'sending' it to the given callback. 243the messages before actually executing the specified callback.
239 244
240B<Please note> that the given callback has to return either a true or a false 245B<Please note> that the every C<rcv> callback has to return either a true
241value for indicating whether it is B<done> (true value) or still wants to 246or a false value, indicating whether it is B<successful>/B<done> (true) or
242B<continue> (false value) receiving messages. 247still wants to B<continue> (false) receiving messages.
243 248
244In this case we tell the C<$client_port> to look into the received messages and 249In this case we tell the C<$client_port> to look into all the messages
245look for the string C<resolved> in the first element of the message. If it is 250it receives and look for the string C<resolved> in the first element of
246found, the given callback will be called with the C<$client_port> as first 251the message. If it is found, the given callback will be called with the
247argument, and the message as the remaining arguments. 252message elements as arguments.
248 253
249We name the first element of the message C<$type> in this case. It's a common 254Using a string as the first element of the message is called I<tagging>
250idiom to code the 'type' of a message into it's first element, this allows for 255the message. It's common practise to code the 'type' of a message into
251simple matching. 256it's first element, as this allows for simple matching.
252 257
253The result message will contain the I<port id> of the well known port C<chatter> 258The result message will contain the I<port ID> of the well known port
254as next element, and will be put in C<$chatter_port_id>. 259C<chatter> as second element, which will be stored in C<$chatter_port_id>.
255 260
256Next we just assign C<$server_port> and return a 1 (a true value) 261This port ID will then be stored in C<$server_port>, followed by calling
257from the callback. It indicates that we are done and don't want to receive 262C<send> on $resolved_cv> so the program will continue.
258further C<resolved> messages with this callback.
259 263
260Now we continue to the rest of the client by calling C<send> on 264The callback then returns a C<1> (a true value), to indicate that it has
261C<$resolved_cv>. 265done it's job and doesn't want to receive further C<resolved> messages.
262 266
263First new step after this is setting up the chat message receiver callback. 267After this the chat message receiver callback is registered with the port:
264 268
265 $client_port->rcv (message => sub { 269 rcv $client_port, message => sub {
266 my ($client_port, $type, $msg) = @_; 270 my ($tag, $msg) = @_;
267 271
268 print "chat> $msg\n"; 272 print "chat> $msg\n";
273
269 0 274 0
270 }); 275 };
271 276
272We assume that all messages that are broadcast to all clients by the server 277We assume that all messages that are broadcast to the clients by the
273will contain the string C<message> as first element, and the actual message as 278server contain the string tag C<message> as first element, and the actual
274second element. The callback returns a false value this time, to indicate that 279message as second element. The callback returns a false value this time,
275it wants to continue receiving messages. 280to indicate that it is not yet done and wants to receive further messages.
276 281
277Last but not least we actually tell the server to send us 282The last thing to do is to tell the server to send us new chat messages
278the new chat messages from other clients. We do so by sending the 283from other clients. We do so by sending the message C<join> followed by
279message type C<join> followed by our own I<port id>. 284our own I<port ID>.
280 285
281 # send the server a 'join' message: 286 # send the server a 'join' message:
282 snd $server_port, join => "$client_port"; 287 snd $server_port, join => $client_port;
283 288
284Then the server knows where to send all the new messages to. 289This way the server knows where to send all the new messages to.
285 290
286=head1 The Completed Client 291=head1 The Completed Client
287 292
288This is the complete client script: 293This is the complete client script:
289 294

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines