summaryrefslogtreecommitdiff
path: root/qpid/doc/book/src/NET-User-Guide.xml
diff options
context:
space:
mode:
Diffstat (limited to 'qpid/doc/book/src/NET-User-Guide.xml')
-rw-r--r--qpid/doc/book/src/NET-User-Guide.xml1383
1 files changed, 1383 insertions, 0 deletions
diff --git a/qpid/doc/book/src/NET-User-Guide.xml b/qpid/doc/book/src/NET-User-Guide.xml
new file mode 100644
index 0000000000..7bfa20b8c8
--- /dev/null
+++ b/qpid/doc/book/src/NET-User-Guide.xml
@@ -0,0 +1,1383 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied. See the License for the
+ specific language governing permissions and limitations
+ under the License.
+
+-->
+
+<section>
+ <title>
+ Apache Qpid: Open Source AMQP Messaging - .NET User Guide
+ </title>
+ <section role="h1" id="NETUserGuide-Tutorial">
+ <title>
+ Tutorial
+ </title>
+ <para>
+ This tutorial consists of a series of examples using the three
+ most commonly used exchange types - Direct, Fanout and
+ Topic
+ exchanges. These examples show how to write applications that use
+ the most common messaging paradigms.
+ </para>
+ <itemizedlist>
+ <listitem>
+ <para>direct</para>
+ <para>In the direct examples, a message producer writes to the direct
+ exchange, specifying a routing key. A message consumer reads
+ messages from a named queue. This illustrates clean separation
+ of concerns - message producers need to know only the exchange
+ and the routing key, message consumers need to know only which
+ queue to use on the broker.
+ </para>
+ </listitem>
+ <listitem>
+ <para>fanout</para>
+ <para>The fanout examples use a fanout exchange and do not use
+ routing keys. Each binding specifies that all messages for a
+ given exchange should be delivered to a given queue.
+ </para>
+ </listitem>
+ <listitem>
+ <para>pub-sub</para>
+ <para>In the publish/subscribe examples, a publisher
+ application writes messages to an exchange, specifying a
+ multi-part key. A subscriber application subscribes to
+ messages that match the relevant parts of these keys, using a
+ private queue for each subscription.
+ </para>
+ </listitem>
+ <listitem>
+ <para>request-response</para>
+ <para>In the request/response examples, a simple service accepts
+ requests from clients and sends responses back to them. Clients
+ create their own private queues and corresponding routing keys.
+ When a client sends a request to the server, it specifies its
+ own routing key in the reply-to field of the request. The
+ server uses the client's reply-to field as the routing key for
+ the response.
+ </para>
+ </listitem>
+ </itemizedlist>
+ <section role="h2" id="NETUserGuide-RunningtheExamples">
+ <title>
+ Running the
+ Examples
+ </title>
+ <para>
+ Before running the examples, you need to unzip the file
+ Qpid.NET-net-2.0-M4.zip, the following tree is created:
+ </para>
+
+
+ <programlisting>
+&lt;home&gt;
+ |-qpid
+ |-lib (contains the required dlls)
+ |-examples
+ |- direct
+ | |-example-direct-Listener.exe
+ | |-example-direct-Producer.exe
+ |- fanout
+ | |-example-fanout-Listener.exe
+ | |-example-fanout-Producer.exe
+ |- pub-sub
+ | |-example-pub-sub-Listener.exe
+ | |-example-pub-sub-Publisher.exe
+ |- request-response
+ |-example-request-response-Client.exe
+ |-example-request-response-Server.exe
+ </programlisting>
+
+
+ <para>
+ Make sure your PATH contains the directory
+ &lt;home&gt;/qpid/lib
+ The examples can be run by executing the provided exe files:
+ </para>
+
+
+ <programlisting>
+$ cd &lt;home&gt;/qpid/examples/examplefolder
+$ example-...-.exe [hostname] [portnumber]
+ </programlisting>
+
+
+ <para>
+ where [hostname] is the qpid broker host name
+ (default is localhost) and [portnumber] is the port number on which the
+ qpid broker is accepting connection (default is 5672).
+ </para>
+ <!--h2-->
+ </section>
+
+ <section role="h2" id="NETUserGuide-CreatingandClosingSessions">
+ <title>
+ Creating
+ and Closing Sessions
+ </title>
+
+ <para>
+ All of the examples have been written using the Apache Qpid .NEt
+ 0.10 API. The examples use the same skeleton code to initialize
+ the program, create a session, and clean up before exiting:
+ </para>
+
+
+ <programlisting>
+using System;
+using System.IO;
+using System.Text;
+using System.Threading;
+using org.apache.qpid.client;
+using org.apache.qpid.transport;
+
+...
+
+ private static void Main(string[] args)
+ {
+ string host = args.Length &gt; 0 ? args[0] : "localhost";
+ int port = args.Length &gt; 1 ? Convert.ToInt32(args[1]) : 5672;
+ Client connection = new Client();
+ try
+ {
+ connection.connect(host, port, "test", "guest", "guest");
+ ClientSession session = connection.createSession(50000);
+
+ //--------- Main body of program --------------------------------------------
+
+ connection.close();
+ }
+ catch (Exception e)
+ {
+ Console.WriteLine("Error: \n" + e.StackTrace);
+ }
+ }
+...
+ </programlisting>
+ <!--h2-->
+ </section>
+
+ <section role="h2" id="NETUserGuide-WritingDirectApplications">
+ <title>
+ Writing
+ Direct Applications
+ </title>
+
+ <para>
+ This section describes two programs that implement direct
+ messaging using a Direct exchange:
+ • org.apache.qpid.example.direct.Producer (from
+ example-direct-producer) publishes messages to the amq.direct
+ exchange, using the routing key routing_key.
+ •org.apache.qpid.example.direct.Listener (from
+ example-direct-Listener) uses a message listener to receive
+ messages from the queue named message_queue.
+ </para>
+ <section role="h3" id="NETUserGuide-RunningtheDirectExamples">
+ <title>
+ Running the
+ Direct Examples
+ </title>
+ <para>
+ 1) Make sure your PATH contains the directory
+ &lt;home&gt;/qpid/lib
+ </para>
+ <para>
+ 2) Make sure that a qpid broker is running:
+ </para>
+
+
+ <programlisting>
+$ ps -eaf | grep qpidd
+ </programlisting>
+
+
+ <para>
+ If a broker is running, you should see the qpidd process in the
+ output of the above
+ command.
+ </para>
+ <para>
+ 3) Read the messages from the message queue using direct
+ listener, as follows:
+ </para>
+
+
+ <programlisting>
+$ cd &lt;home&gt;/qpid/examples/direct
+ </programlisting>
+
+
+ <para>
+ With cygwin:
+ </para>
+
+
+ <programlisting>
+$ ./example-direct-Listener.exe [hostname] [portnumber]
+ </programlisting>
+
+
+ <para>
+ or with mono:
+ </para>
+
+
+ <programlisting>
+$ mono ./example-direct-Listener.exe [hostname] [portnumber]
+ </programlisting>
+
+
+ <para>
+ This program is waiting for messages to be published, see next
+ step:
+ </para>
+ <para>
+ 4) Publish a series of messages to the amq.direct exchange by
+ running direct producer, as follows:
+ </para>
+
+
+ <programlisting>
+$ cd &lt;home&gt;/qpid/examples/direct
+ </programlisting>
+
+
+ <para>
+ With cygwin:
+ </para>
+
+
+ <programlisting>
+$ ./example-direct-Producer.exe [hostname] [portnumber]
+ </programlisting>
+
+
+ <para>
+ or with mono:
+ </para>
+
+
+ <programlisting>
+$ mono ./example-direct-Producer.exe [hostname] [portnumber]
+ </programlisting>
+
+
+ <para>
+ This program has no output; the messages are routed to the
+ message queue, as instructed by the binding.
+ </para>
+ <para>
+ 5) Go to the windows where you are running your listener. You
+ should see the following output:
+ </para>
+
+
+ <programlisting>
+Message: Message 0
+Message: Message 1
+Message: Message 2
+Message: Message 3
+Message: Message 4
+Message: Message 5
+Message: Message 6
+Message: Message 7
+Message: Message 8
+Message: Message 9
+Message: That's all, folks!
+ </programlisting>
+
+
+ <para>
+ Now we will examine the code for each of these programs. In each
+ section, we will discuss only
+ the code that must be added to the skeleton shown in Section
+ "Creating and Closing Sessions".
+ </para>
+ <!--h3-->
+ </section>
+
+ <section role="h3" id="NETUserGuide-ReadingMessagesfromtheQueue">
+ <title>
+ Reading
+ Messages from the Queue
+ </title>
+
+ <para>
+ The program , listener.cs, is a message listener that receives
+ messages from a queue.
+ </para>
+ <para>
+ First it creates a queue named message_queue, then binds it to
+ the amq.direct exchange using the binding key routing_key.
+ </para>
+
+
+ <programlisting>
+//--------- Main body of program --------------------------------------------
+// Create a queue named "message_queue", and route all messages whose
+// routing key is "routing_key" to this newly created queue.
+session.queueDeclare("message_queue");
+session.exchangeBind("message_queue", "amq.direct", "routing_key");
+ </programlisting>
+
+
+ <para>
+ The queue created by this program continues to exist after the
+ program exits, and any message whose routing key matches the key
+ specified in the binding will be routed to the corresponding
+ queue by the broker. Note that the queue could have been be
+ deleted using the following code:
+ </para>
+
+
+ <programlisting>
+session.queueDelete("message_queue");
+ </programlisting>
+
+
+ <para>
+ To create a message listener, create a class derived from
+ IMessageListener, and override the messageTransfer method,
+ providing the code that should be executed when a message is
+ received.
+ </para>
+
+
+ <programlisting>
+public class MessageListener : IMessageListener
+{
+ ......
+ public void messageTransfer(IMessage m)
+ {
+ .....
+}
+ </programlisting>
+
+
+ <para>
+ The main body of the program creates a listener for the
+ subscription; attaches the listener to a message queue; and
+ subscribe to the queue to receive messages from the queue.
+ </para>
+
+
+ <programlisting>
+lock (session)
+{
+ // Create a listener and subscribe it to the queue named "message_queue"
+ IMessageListener listener = new MessageListener(session);
+ session.attachMessageListener(listener, "message_queue");
+ session.messageSubscribe("message_queue");
+ // Receive messages until all messages are received
+ Monitor.Wait(session);
+}
+ </programlisting>
+
+
+ <para>
+ The MessageListener's messageTransfer() function is called
+ whenever a message is received. In this example the message is
+ printed and tested to see if it is the final message. Once the
+ final message is received, the messages are acknowledged.
+ </para>
+
+
+ <programlisting>
+BinaryReader reader = new BinaryReader(m.Body, Encoding.UTF8);
+byte[] body = new byte[m.Body.Length - m.Body.Position];
+reader.Read(body, 0, body.Length);
+ASCIIEncoding enc = new ASCIIEncoding();
+string message = enc.GetString(body);
+ Console.WriteLine("Message: " + message);
+// Add this message to the list of message to be acknowledged
+_range.add(m.Id);
+if( message.Equals("That's all, folks!") )
+{
+ // Acknowledge all the received messages
+ _session.messageAccept(_range);
+ lock(_session)
+ {
+ Monitor.Pulse(_session);
+ }
+}
+ </programlisting>
+ <!--h3-->
+ </section>
+
+ <section role="h3" id="NETUserGuide-PublishingMessagestoaDirectExchange">
+ <title>
+ Publishing
+ Messages to a Direct Exchange
+ </title>
+ <para>
+ The second program in the direct example, Producer.cs, publishes
+ messages to the amq.direct exchange using the routing key
+ routing_key.
+ </para>
+ <para>
+ First, create a message and set a routing key. The same routing
+ key will be used for each message we send, so you only need to
+ set this property once.
+ </para>
+
+
+ <programlisting>
+IMessage message = new Message();
+// The routing key is a message property. We will use the same
+// routing key for each message, so we'll set this property
+// just once. (In most simple cases, there is no need to set
+// other message properties.)
+message.DeliveryProperties.setRoutingKey("routing_key");
+ </programlisting>
+
+
+ <para>
+ Now send some messages:
+ </para>
+
+
+ <programlisting>
+// Asynchronous transfer sends messages as quickly as
+// possible without waiting for confirmation.
+for (int i = 0; i &lt; 10; i++)
+{
+ message.clearData();
+ message.appendData(Encoding.UTF8.GetBytes("Message " + i));
+ session.messageTransfer("amq.direct", message);
+}
+ </programlisting>
+
+
+ <para>
+ Send a final synchronous message to indicate termination:
+ </para>
+
+
+ <programlisting>
+// And send a syncrhonous final message to indicate termination.
+message.clearData();
+message.appendData(Encoding.UTF8.GetBytes("That's all, folks!"));
+session.messageTransfer("amq.direct", "routing_key", message);
+session.sync();
+ </programlisting>
+ <!--h3-->
+ </section>
+
+ <!--h2-->
+ </section>
+
+
+ <section role="h2" id="NETUserGuide-WritingFanoutApplications">
+ <title>
+ Writing
+ Fanout Applications
+ </title>
+
+ <para>
+ This section describes two programs that illustrate the use of a
+ Fanout exchange.
+ </para>
+ <itemizedlist>
+ <listitem>
+ <para>Listener.cs makes a unique queue private for each instance of
+ the listener, and binds that queue to the fanout exchange. All
+ messages sent to the fanout exchange are delivered to each
+ listener's queue.
+ </para>
+ </listitem>
+ <listitem>
+ <para>Producer.cs publishes messages to the fanout exchange. It
+ does not use a routing key, which is not needed by the fanout
+ exchange.
+ </para>
+ </listitem>
+ </itemizedlist>
+ <section role="h3" id="NETUserGuide-RunningtheFanoutExamples">
+ <title>
+ Running the
+ Fanout Examples
+ </title>
+
+ <para>
+ 1) Make sure your PATH contains the directory
+ &lt;home&gt;/qpid/lib
+ </para>
+ <para>
+ 2) Make sure that a qpid broker is running:
+ </para>
+
+
+ <programlisting>
+$ ps -eaf | grep qpidd
+ </programlisting>
+
+
+ <para>
+ If a broker is running, you should see the qpidd process in the
+ output of the above
+ command.
+ </para>
+ <para>
+ 3) In separate windows, start one or more fanout listeners as
+ follows:
+ </para>
+
+
+ <programlisting>
+$ cd &lt;home&gt;/qpid/examples/direct
+ </programlisting>
+
+
+ <para>
+ With cygwin:
+ </para>
+
+
+ <programlisting>
+$ ./example-fanout-Listener.exe [hostname] [portnumber]
+ </programlisting>
+
+
+ <para>
+ or with mono:
+ </para>
+
+
+ <programlisting>
+$ mono ./example-fanout-Listener.exe [hostname] [portnumber]
+ </programlisting>
+
+
+ <para>
+ The listener creates a private queue, binds it to the amq.fanout
+ exchange, and waits for messages to arrive on the queue. When the
+ listener starts, you will see the following message:
+ </para>
+
+
+ <programlisting>
+Listening
+ </programlisting>
+
+
+ <para>
+ This program is waiting for messages to be published, see next
+ step:
+ </para>
+ <para>
+ 4) In a separate window, publish a series of messages to the
+ amq.fanout exchange by running fanout producer, as follows:
+ </para>
+
+
+ <programlisting>
+$ cd &lt;home&gt;/qpid/examples/direct
+ </programlisting>
+
+
+ <para>
+ With cygwin:
+ </para>
+
+
+ <programlisting>
+$ ./example-fanout-Producer.exe [hostname] [portnumber]
+ </programlisting>
+
+
+ <para>
+ or with mono:
+ </para>
+
+
+ <programlisting>
+$ mono ./example-fanout-Producer.exe [hostname] [portnumber]
+ </programlisting>
+
+
+ <para>
+ This program has no output; the messages are routed to the
+ message queue, as prescribed by the binding.
+ </para>
+ <para>
+ 5) Go to the windows where you are running listeners. You should
+ see the following output for each listener:
+ </para>
+
+
+ <programlisting>
+Message: Message 0
+Message: Message 1
+Message: Message 2
+Message: Message 3
+Message: Message 4
+Message: Message 5
+Message: Message 6
+Message: Message 7
+Message: Message 8
+Message: Message 9
+Message: That's all, folks!
+ </programlisting>
+
+
+ <para>
+ Now we will examine the code for each of these programs. In each
+ section, we will discuss only
+ the code that must be added to the skeleton shown in Section
+ "Creating and Closing Sessions".
+ </para>
+
+ <!--h3-->
+ </section>
+
+ <!--h2-->
+ </section>
+
+ <section role="h2" id="NETUserGuide-ConsumingfromaFanoutExchange">
+ <title>
+ Consuming from a
+ Fanout Exchange
+ </title>
+
+ <para>
+ The first program in the fanout example, Listener.cs, creates a
+ private queue, binds it to the amq.fanout exchange, and waits for
+ messages to arrive on the queue, printing them out as they
+ arrive. It uses a Listener that is identical to the one used in
+ the direct example:
+ </para>
+
+
+ <programlisting>
+ public class MessageListener : IMessageListener
+ {
+ private readonly ClientSession _session;
+ private readonly RangeSet _range = new RangeSet();
+ public MessageListener(ClientSession session)
+ {
+ _session = session;
+ }
+
+ public void messageTransfer(IMessage m)
+ {
+ BinaryReader reader = new BinaryReader(m.Body, Encoding.UTF8);
+ byte[] body = new byte[m.Body.Length - m.Body.Position];
+ reader.Read(body, 0, body.Length);
+ ASCIIEncoding enc = new ASCIIEncoding();
+ string message = enc.GetString(body);
+ Console.WriteLine("Message: " + message);
+ // Add this message to the list of message to be acknowledged
+ _range.add(m.Id);
+ if (message.Equals("That's all, folks!"))
+ {
+ // Acknowledge all the received messages
+ _session.messageAccept(_range);
+ lock (_session)
+ {
+ Monitor.Pulse(_session);
+ }
+ }
+ }
+ }
+ </programlisting>
+
+
+ <para>
+ The listener creates a private queue to receive its messages and
+ binds it to the fanout exchange:
+ </para>
+
+
+ <programlisting>
+string myQueue = session.Name;
+session.queueDeclare(myQueue, Option.EXCLUSIVE, Option.AUTO_DELETE);
+session.exchangeBind(myQueue, "amq.fanout", "my-key");
+ </programlisting>
+
+
+ <para>
+ Now we create a listener and subscribe it to the queue:
+ </para>
+
+
+ <programlisting>
+lock (session)
+{
+ Console.WriteLine("Listening");
+ // Create a listener and subscribe it to my queue.
+ IMessageListener listener = new MessageListener(session);
+ session.attachMessageListener(listener, myQueue);
+ session.messageSubscribe(myQueue);
+ // Receive messages until all messages are received
+ Monitor.Wait(session);
+}
+ </programlisting>
+
+
+ <section role="h3" id="NETUserGuide-PublishingMessagestotheFanoutExchange">
+ <title>
+ Publishing
+ Messages to the Fanout Exchange
+ </title>
+
+ <para>
+ The second program in this example, Producer.cs, writes messages
+ to the fanout queue.
+ </para>
+
+
+ <programlisting>
+// Unlike topic exchanges and direct exchanges, a fanout
+// exchange need not set a routing key.
+IMessage message = new Message();
+// Asynchronous transfer sends messages as quickly as
+// possible without waiting for confirmation.
+for (int i = 0; i &lt; 10; i++)
+{
+ message.clearData();
+ message.appendData(Encoding.UTF8.GetBytes("Message " + i));
+ session.messageTransfer("amq.fanout", message);
+}
+
+// And send a syncrhonous final message to indicate termination.
+message.clearData();
+message.appendData(Encoding.UTF8.GetBytes("That's all, folks!"));
+session.messageTransfer("amq.fanout", message);
+session.sync();
+ </programlisting>
+
+ <!--h3-->
+ </section>
+
+ <!--h2-->
+ </section>
+
+ <section role="h2" id="NETUserGuide-WritingPublish-2FSubscribeApplications">
+ <title>
+ Writing
+ Publish/Subscribe Applications
+ </title>
+
+ <para>
+ This section describes two programs that implement
+ Publish/Subscribe messaging using a topic exchange.
+ </para>
+ <para>
+ • Publisher.cS sends messages to the amq.topic exchange,
+ using the multipart routing keys usa.news, usa.weather,
+ europe.news, and europe.weather.
+ • Listener.cs creates private queues for news, weather,
+ usa, and europe, binding them to the amq.topic exchange using
+ bindings that match the corresponding parts of the multipart
+ routing keys.
+ </para>
+ <para>
+ In this example, the publisher creates messages for topics like
+ news, weather, and sports that happen in regions like Europe,
+ Asia, or the United States. A given consumer may be interested in
+ all weather messages, regardless of region, or it may be
+ interested in news and weather for the United States, but
+ uninterested in items for other regions. In this example, each
+ consumer sets up its own private queues, which receive precisely
+ the messages that particular consumer is interested in.
+ </para>
+ <section role="h3" id="NETUserGuide-RunningthePublishSubscribeExamples">
+ <title>
+ Running
+ the Publish-Subscribe Examples
+ </title>
+ <para>
+ 1) Make sure your PATH contains the directory
+ &lt;home&gt;/qpid/lib
+ </para>
+ <para>
+ 2) Make sure that a qpid broker is running:
+ </para>
+
+
+ <programlisting>
+$ ps -eaf | grep qpidd
+ </programlisting>
+
+
+ <para>
+ If a broker is running, you should see the qpidd process in the
+ output of the above
+ command.
+ </para>
+ <para>
+ 3) In separate windows, start one or more topic subscribers as
+ follows:
+ </para>
+
+
+ <programlisting>
+$ cd &lt;home&gt;/qpid/examples/direct
+ </programlisting>
+
+
+ <para>
+ With cygwin:
+ </para>
+
+
+ <programlisting>
+$ ./example-pub-sub--Listener.exe [hostname] [portnumber]
+ </programlisting>
+
+
+ <para>
+ or with mono:
+ </para>
+
+
+ <programlisting>
+$ mono ./example-pub-sub-Listener.exe [hostname] [portnumber]
+ </programlisting>
+
+
+ <para>
+ You will see output similar to this:
+ </para>
+
+
+ <programlisting>
+Listening for messages ...
+Declaring queue: usa
+Declaring queue: europe
+Declaring queue: news
+Declaring queue: weather
+ </programlisting>
+
+
+ <para>
+ Each topic consumer creates a set of private queues, and binds
+ each queue to the amq.topic exchange together with a binding that
+ indicates which messages should be routed to the queue.
+ </para>
+ <para>
+ 4) In another window, start the topic publisher, which publishes
+ messages to the amq.topic exchange, as follows:
+ </para>
+
+
+ <programlisting>
+$ cd &lt;home&gt;/qpid/examples/direct
+ </programlisting>
+
+
+ <para>
+ With cygwin:
+ </para>
+
+
+ <programlisting>
+$ ./example-pub-sub-Producer.exe [hostname] [portnumber]
+ </programlisting>
+
+
+ <para>
+ or with mono:
+ </para>
+
+
+ <programlisting>
+$ mono ./example-pub-sub-Producer.exe [hostname] [portnumber]
+ </programlisting>
+
+
+ <para>
+ This program has no output; the messages are routed to the
+ message queues for each topic_consumer as specified by the
+ bindings the consumer created.
+ </para>
+ <para>
+ 5) Go back to the window for each topic consumer. You should see
+ output like this:
+ </para>
+
+
+ <programlisting>
+Message: Message 0 from usa
+Message: Message 0 from news
+Message: Message 0 from weather
+Message: Message 1 from usa
+Message: Message 1 from news
+Message: Message 2 from usa
+Message: Message 2 from news
+Message: Message 3 from usa
+Message: Message 3 from news
+Message: Message 4 from usa
+Message: Message 4 from news
+Message: Message 5 from usa
+Message: Message 5 from news
+Message: Message 6 from usa
+Message: Message 6 from news
+Message: Message 7 from usa
+Message: Message 7 from news
+Message: Message 8 from usa
+Message: Message 8 from news
+Message: Message 9 from usa
+....
+Message: That's all, folks! from weather
+Shutting down listener for control
+Message: That's all, folks! from europe
+Shutting down listener for control
+ </programlisting>
+
+
+ <para>
+ Now we will examine the code for each of these programs. In each
+ section, we will discuss only
+ the code that must be added to the skeleton shown in Section
+ "Creating and Closing Sessions".
+ </para>
+ <!--h3-->
+ </section>
+
+
+ <section role="h3" id="NETUserGuide-PublishingMessagestoaTopicExchange">
+ <title>
+ Publishing
+ Messages to a Topic Exchange
+ </title>
+
+ <para>
+ The first program in the publish/subscribe example, Publisher.cs,
+ defines two new functions: one that publishes messages to the
+ topic exchange, and one that indicates that no more messages are
+ coming.
+ </para>
+ <para>
+ The publishMessages function publishes a series of five messages
+ using the specified routing key.
+ </para>
+
+
+ <programlisting>
+private static void publishMessages(ClientSession session, string routing_key)
+{
+ IMessage message = new Message();
+ // Asynchronous transfer sends messages as quickly as
+ // possible without waiting for confirmation.
+ for (int i = 0; i &lt; 10; i++)
+ {
+ message.clearData();
+ message.appendData(Encoding.UTF8.GetBytes("Message " + i));
+ session.messageTransfer("amq.topic", routing_key, message);
+ }
+}
+ </programlisting>
+
+
+ <para>
+ The noMoreMessages function signals the end of messages using the
+ control routing key, which is reserved for control messages.
+ </para>
+
+
+ <programlisting>
+private static void noMoreMessages(ClientSession session)
+{
+ IMessage message = new Message();
+ // And send a syncrhonous final message to indicate termination.
+ message.clearData();
+ message.appendData(Encoding.UTF8.GetBytes("That's all, folks!"));
+ session.messageTransfer("amq.topic", "control", message);
+ session.sync();
+}
+ </programlisting>
+
+
+ <para>
+ In the main body of the program, messages are published using
+ four different routing keys, and then the end of messages is
+ indicated by a message sent to a separate routing key.
+ </para>
+
+
+ <programlisting>
+publishMessages(session, "usa.news");
+publishMessages(session, "usa.weather");
+publishMessages(session, "europe.news");
+publishMessages(session, "europe.weather");
+
+noMoreMessages(session);
+ </programlisting>
+ <!--h3-->
+ </section>
+
+ <section role="h3" id="NETUserGuide-ReadingMessagesfromtheQueue2">
+ <title>
+ Reading
+ Messages from the Queue
+ </title>
+
+ <para>
+ The second program in the publish/subscribe example, Listener.cs,
+ creates a local private queue, with a unique name, for each of
+ the four binding keys it specifies: usa.#, europe.#, #.news, and
+ #.weather, and creates a listener.
+ </para>
+
+
+ <programlisting>
+Console.WriteLine("Listening for messages ...");
+// Create a listener
+prepareQueue("usa", "usa.#", session);
+prepareQueue("europe", "europe.#", session);
+prepareQueue("news", "#.news", session);
+prepareQueue("weather", "#.weather", session);
+ </programlisting>
+
+
+ <para>
+ The prepareQueue() method creates a queue using a queue name and
+ a routing key supplied as arguments it then attaches a listener
+ with the session for the created queue and subscribe for this
+ receiving messages from the queue:
+ </para>
+
+
+ <programlisting>
+// Create a unique queue name for this consumer by concatenating
+// the queue name parameter with the Session ID.
+Console.WriteLine("Declaring queue: " + queue);
+session.queueDeclare(queue, Option.EXCLUSIVE, Option.AUTO_DELETE);
+
+// Route messages to the new queue if they match the routing key.
+// Also route any messages to with the "control" routing key to
+// this queue so we know when it's time to stop. A publisher sends
+// a message with the content "That's all, Folks!", using the
+// "control" routing key, when it is finished.
+
+session.exchangeBind(queue, "amq.topic", routing_key);
+session.exchangeBind(queue, "amq.topic", "control");
+
+// subscribe the listener to the queue
+IMessageListener listener = new MessageListener(session);
+session.attachMessageListener(listener, queue);
+session.messageSubscribe(queue);
+ </programlisting>
+ <!--h3-->
+ </section>
+ <!--h2-->
+ </section>
+
+ <section role="h2" id="NETUserGuide-WritingRequest-2FResponseApplications">
+ <title>
+ Writing
+ Request/Response Applications
+ </title>
+
+ <para>
+ In the request/response examples, we write a server that accepts
+ strings from clients and converts them to upper case, sending the
+ result back to the requesting client. This example consists of
+ two programs.
+ </para>
+ <itemizedlist>
+ <listitem>
+ <para>Client.cs is a client application that sends messages to the
+ server.
+ • Server.cs is a service that accepts messages, converts
+ their content to upper case, and sends the result to the
+ amq.direct exchange, using the request's reply-to property as
+ the routing key for the response.
+ </para>
+ </listitem>
+ </itemizedlist>
+ <section role="h3" id="NETUserGuide-RunningtheRequest-2FResponseExamples">
+ <title>
+ Running
+ the Request/Response Examples
+ </title>
+ <para>
+ 1) Make sure your PATH contains the directory
+ &lt;home&gt;/qpid/lib
+ </para>
+ <para>
+ 2) Make sure that a qpid broker is running:
+ </para>
+
+
+ <programlisting>
+$ ps -eaf | grep qpidd
+ </programlisting>
+
+
+ <para>
+ If a broker is running, you should see the qpidd process in the
+ output of the above
+ command.
+ </para>
+ <para>
+ 3) Run the server.
+ </para>
+ <para>
+ $ cd &lt;home&gt;/qpid/examples/direct
+ </para>
+
+
+ <programlisting>
+ With cygwin:
+ </programlisting>
+
+
+ <para>
+ $ ./example-request-response-Server.exe [hostname] [portnumber]
+ </para>
+
+
+ <programlisting>
+ or with mono:
+ </programlisting>
+
+
+ <para>
+ $ mono ./example-request-response-Server.exe [hostname] [portnumber]
+ </para>
+
+
+ <programlisting>
+ You will see output similar to this:
+ </programlisting>
+
+
+ <para>
+ Waiting for requests
+ </para>
+
+
+ <programlisting>
+4) In a separate window, start a client:
+
+$ cd &lt;home&gt;/qpid/examples/direct
+ </programlisting>
+
+
+ <para>
+ With cygwin:
+ </para>
+
+
+ <programlisting>
+$ ./example-request-response-Client.exe [hostname] [portnumber]
+ </programlisting>
+
+
+ <para>
+ or with mono:
+ </para>
+
+
+ <programlisting>
+$ mono ./example-request-response-Client.exe [hostname] [portnumber]
+ </programlisting>
+
+
+ <para>
+ You will see output similar to this:
+ </para>
+
+
+ <programlisting>
+Activating response queue listener for: clientSystem.Byte[]
+Waiting for all responses to arrive ...
+Response: TWAS BRILLIG, AND THE SLITHY TOVES
+Response: DID GIRE AND GYMBLE IN THE WABE.
+Response: ALL MIMSY WERE THE BOROGROVES,
+Response: AND THE MOME RATHS OUTGRABE.
+Shutting down listener for clientSystem.Byte[]
+Response: THAT'S ALL, FOLKS!
+ </programlisting>
+
+
+ <para>
+ 4) Go back to the server window, the output should be similar to
+ this:
+ </para>
+
+
+ <programlisting>
+Waiting for requests
+Request: Twas brillig, and the slithy toves
+Request: Did gire and gymble in the wabe.
+Request: All mimsy were the borogroves,
+Request: And the mome raths outgrabe.
+Request: That's all, folks!
+ </programlisting>
+
+
+ <para>
+ Now we will examine the code for each of these programs. In each
+ section, we will discuss only the code that must be added to the
+ skeleton shown in Section "Creating and Closing Sessions".
+ </para>
+ <!--h3-->
+ </section>
+
+
+ <section role="h3" id="NETUserGuide-TheClientApplication">
+ <title>
+ The Client
+ Application
+ </title>
+
+ <para>
+ The first program in the request-response example, Client.cs,
+ sets up a private response queue to receive responses from the
+ server, then sends messages the server, listening to the response
+ queue for the server's responses.
+ </para>
+
+
+ <programlisting>
+string response_queue = "client" + session.getName();
+// Use the name of the response queue as the routing key
+session.queueDeclare(response_queue);
+session.exchangeBind(response_queue, "amq.direct", response_queue);
+
+// Create a listener for the response queue and listen for response messages.
+Console.WriteLine("Activating response queue listener for: " + response_queue);
+IMessageListener listener = new ClientMessageListener(session);
+session.attachMessageListener(listener, response_queue);
+session.messageSubscribe(response_queue);
+ </programlisting>
+
+
+ <para>
+ Set some properties that will be used for all requests. The
+ routing key for a request is request.
+ The reply-to property is set to the routing key for the client's
+ private queue.
+ </para>
+
+
+ <programlisting>
+IMessage request = new Message();
+request.DeliveryProperties.setRoutingKey("request");
+request.MessageProperties.setReplyTo(new ReplyTo("amq.direct", response_queue));
+ </programlisting>
+
+
+ <para>
+ Now send some requests...
+ </para>
+
+
+ <programlisting>
+string[] strs = {
+ "Twas brillig, and the slithy toves",
+ "Did gire and gymble in the wabe.",
+ "All mimsy were the borogroves,",
+ "And the mome raths outgrabe.",
+ "That's all, folks!"
+ };
+foreach (string s in strs)
+{
+ request.clearData();
+ request.appendData(Encoding.UTF8.GetBytes(s));
+ session.messageTransfer("amq.direct", request);
+}
+ </programlisting>
+
+
+ <para>
+ And wait for responses to arrive:
+ </para>
+
+
+ <programlisting>
+Console.WriteLine("Waiting for all responses to arrive ...");
+Monitor.Wait(session);
+ </programlisting>
+ <!--h3-->
+ </section>
+
+ <section role="h3" id="NETUserGuide-TheServerApplication">
+ <title>
+ The Server
+ Application
+ </title>
+
+ <para>
+ The second program in the request-response example, Server.cs,
+ uses the reply-to property as the routing key for responses.
+ </para>
+ <para>
+ The main body of Server.cs creates an exclusive queue for
+ requests, then waits for messages to arrive.
+ </para>
+
+
+ <programlisting>
+const string request_queue = "request";
+// Use the name of the request queue as the routing key
+session.queueDeclare(request_queue);
+session.exchangeBind(request_queue, "amq.direct", request_queue);
+
+lock (session)
+{
+ // Create a listener and subscribe it to the request_queue
+ IMessageListener listener = new MessageListener(session);
+ session.attachMessageListener(listener, request_queue);
+ session.messageSubscribe(request_queue);
+ // Receive messages until all messages are received
+ Console.WriteLine("Waiting for requests");
+ Monitor.Wait(session);
+}
+ </programlisting>
+
+
+ <para>
+ The listener's messageTransfer() method converts the request's
+ content to upper case, then sends a response to the broker, using
+ the request's reply-to property as the routing key for the
+ response.
+ </para>
+
+
+ <programlisting>
+BinaryReader reader = new BinaryReader(request.Body, Encoding.UTF8);
+byte[] body = new byte[request.Body.Length - request.Body.Position];
+reader.Read(body, 0, body.Length);
+ASCIIEncoding enc = new ASCIIEncoding();
+string message = enc.GetString(body);
+Console.WriteLine("Request: " + message);
+
+// Transform message content to upper case
+string responseBody = message.ToUpper();
+
+// Send it back to the user
+response.clearData();
+response.appendData(Encoding.UTF8.GetBytes(responseBody));
+_session.messageTransfer("amq.direct", routingKey, response);
+ </programlisting>
+
+ <!--h3-->
+ </section>
+ <!--h2-->
+ </section>
+ <!--h1-->
+ </section>
+
+
+ </section>