官方文档:http://www.rabbitmq.com/tutorials/tutorial-one-python.html
下文为翻译和erlang客户端的例子
RabbitMQ是一个消息中间件,它主要的思想非常简单:接收和发送消息。你可以把RabbitMQ想象成一个邮局:当你把信件放入邮筒的时候你非常确定邮递员会把你的信件投递给信件的接收者。在这个比喻里面,RabbitMQ是一个邮筒,邮局以及邮递员。
RabbitMQ与邮局的主要区别在于,RabbitMQ不处理信件,取而代之的是它接收,存储并且发送二进制数据,也就是所谓的消息。
RabbitMQ 与 messaging 通常情况下,使用一些术语。
生产也就是发送的意思,发送消息的程序叫做生产者,我们把它画成这样,使用"p";
队列是邮箱的名字,它存在于RabbitMQ的内部,虽然消息在RabbitMQ和你的应用程序之间流转,但是消息只能被存储在一个队列里面。队列没有任何限制,只要你愿意,它可以存储任意多个消息,本质上,队列是一个没有限制的buffer。一个队列可以接收多个生产者的消息,多个消费者也可以从一个队列里面接收消息。队列一般用下图表示,上面是队列的名字:
消费其实就是接收的意思。一个消费者就是一个等待接收消息的应用程序。消费者一般用下图表示:
值得注意的是,生产者,消费者和RabbitMQ不需要部署在同一台物理机上,事实上在很多应用里面他们也确实没有部署在同一台物理机上。
Hello World
我们的"Hello world"程序不复杂 :发送一个消息,接收消息和打印到屏幕上。完成这些需要两个程序:一个发送消息程序,和一个接收并打印消息程序。
整体的过程如下:
生产者发送消息到"hello"队列。消费者从这个队列接收消息。
Sending
我们第一个程序 send.erl 将发送一个消息到队列。
1.我们需要建立一个到RabbitMQ server的连接。
{ok, Connection} =amqp_connection:start(#amqp_params_network{host = "localhost"}), {ok, Channel} = amqp_connection:open_channel(Connection),
我们现在已经连接上了一个本地的RabbitMQ服务器,因为我们给的参数是”localhost”。如果我们想连接到不同机器上的RabbitMQ服务器,我们可以把”localhost”改成相应机器的名字或者IP地址。
2:在发送消息之前,我们必须确保接收消息的队列是存在的。如果我们把消息发送到一个不存在的队列,RabbitMQ会把我们的消息当作垃圾,不予处理。让我们来创建一个队列,并且把它命名为hello:
amqp_channel:call(Channel, #'queue.declare'{queue = <<"hello">>}),
现在我们可以准备发送一个消息。第一个消息仅仅包含一个"Hello world!"字符串。我们想要发送到我们的hello 队列。
3:在RabbitMQ里面,消息是不能被直接发送到队列里面去的,在消息发送到队列之前必须要先经过一个“exchange”,现在我们不讨论exchange的具体细节,现在我们只需要知道怎么使用一个由空字符串标志的默认exchange,这个exchange非常特殊---它允许我们指定一个具体的消息要投递的队列。队列的名字在参数routing_key里面指定:
amqp_channel:cast(Channel, #'basic.publish'{ exchange = <<"">>, routing_key = <<"hello">>}, #amqp_msg{payload = <<"Hello World!">>}),
在退出程序之前,我们需要确认刷新网络缓存区,我们的消息真正的发送到RabbitMQ。 我们可以关闭连接来达到这个目的。
ok = amqp_channel:close(Channel), ok = amqp_connection:close(Connection),
Receiving
我们的第二个程序时receive1.erl,将会接收消息从队列并在屏幕上打印出来。
构造消费者应用程序的步骤:
1:建立一个到RabbitMQ服务器的连接,与生产者的步骤一样:
{ok, Connection} = amqp_connection:start(#amqp_params_network{host = "localhost"}), {ok, Channel} = amqp_connection:open_channel(Connection),
2:确保消息队列的存在。我们使用queue_declare来创建队列。queue_declare可以被调用多次,但是只有一个调用会创建queue:
amqp_channel:call(Channel, #'queue.declare'{queue = <<"hello">>})
你可能会问,为什么我们要重复地创建队列---我们已经在生产者那边创建了这个队列。因为你不能保证生产者和消费者谁先启动,所以我们在两边都对队列进行创建操作。
3:从队列接收消息要相对来说复杂些。接收消息通过在队列上绑定一个回调函数来实现,不管什么时候我们接收到一个消息,这个回调函数都会被调用。在hello world这个例子中,回调函数的作用就是把收到的消息打印出来:
amqp_channel:subscribe(Channel, #'basic.consume'{queue = <<"hello">>, no_ack = true}, self()),
loop(Channel) -> receive {#'basic.deliver'{}, #amqp_msg{payload = Body}} -> io:format(" [x] Received ~p~n", [Body]), loop(Channel) end.
4:然后我们告诉RabbitMQ收到消息时,给自己发送消息。
receive #'basic.consume_ok'{} -> ok end,
完整代码
send.erl (发送消息)
-module(send). -compile([export_all]). -include_lib("amqp_client/include/amqp_client.hrl"). main(_) -> {ok, Connection} = amqp_connection:start(#amqp_params_network{host = "localhost"}), {ok, Channel} = amqp_connection:open_channel(Connection), amqp_channel:call(Channel, #'queue.declare'{queue = <<"hello">>}), amqp_channel:cast(Channel, #'basic.publish'{ exchange = <<"">>, routing_key = <<"hello">>}, #amqp_msg{payload = <<"Hello World!">>}), io:format(" [x] Sent 'Hello World!'~n"), ok = amqp_channel:close(Channel), ok = amqp_connection:close(Connection), ok.
receive1.erl(接收消息)
-moudle(receive1). -compile([export_all]). -include_lib("amqp_client/include/amqp_client.hrl"). main(_) -> {ok, Connection} = amqp_connection:start(#amqp_params_network{host = "localhost"}), {ok, Channel} = amqp_connection:open_channel(Connection), amqp_channel:call(Channel, #'queue.declare'{queue = <<"hello">>}), io:format(" [*] Waiting for messages. To exit press CTRL+C~n"), amqp_channel:subscribe(Channel, #'basic.consume'{queue = <<"hello">>, no_ack = true}, self()), receive #'basic.consume_ok'{} -> ok end, loop(Channel). loop(Channel) -> receive {#'basic.deliver'{}, #amqp_msg{payload = Body}} -> io:format(" [x] Received ~p~n", [Body]), loop(Channel) end.