生产者–消费者模式
上一篇讨论了如何搭建我们的开发环境,无论使用哪种语言,服务的部署肯定都是相同的。
摘自官网:RabbitMQ is a message broker. In essence, it accepts messages from producers, and delivers them to consumers. In-between, it can route, buffer, and persist the messages according to rules you give it.(译文:兔子就是消息代理,本质上,它接受来自producers的消息然后分发给consumers,在此过程中,它能够根据你定制的规则来路由、缓存和持久化消息)。
本文开始将基于生产者-消费者模式创建第一个项目,hello world,是否感觉很亲切呢!
既然是生产者-消费者模式,那么显然意味着我们会有生产者和消费者两套程序。生产者负责生产message并推送给queue,而消费者从queue中拉取消息进行处理。
生产者
首先我们需要创建一个控制台应用程序,生产者,即消息发送方,我们创建一个类Send.cs,当然,如果你愿意,也可以叫Producer.cs或者F**k.cs等等。
还记否,上一篇我们已经下载好了驱动,即RabbitMQ.Client.dll,现在只要在此项目中引用即可。
代码中这样引用即可(哎,官网就是这么详细,稍有常识的猿直接跳过)
using System;
using System.Text;
using RabbitMQ.Client;
接下来就可以和RabbitMQ Server创建连接了:
class Send
{
public static void Main()
{
var factory = new ConnectionFactory() { HostName = "localhost" };//创建代理服务器实例。注意:HostName为Rabbit Server所在服务器的ip或域名,如果服务装在本机,则为localhost,默认端口5672
using (var connection = factory.CreateConnection())//创建socket连接
{
using (var channel = connection.CreateModel())//channel中包含几乎所有的api来供我们操作queue
{
...
}
}
}
}
很简单的对不对,接下来给出Send.cs的完整代码,为了方便理解,注释我会写在代码中:
using System;
using RabbitMQ.Client;
using System.Text;
class Send
{
public static void Main()
{
var factory = new ConnectionFactory() { HostName = "localhost" };
using(var connection = factory.CreateConnection())
using(var channel = connection.CreateModel())
{
//声明queue
channel.QueueDeclare(queue: "hello",//队列名
durable: false,//是否持久化
exclusive: false,//true:排他性,该队列仅对首次申明它的连接可见,并在连接断开时自动删除
autoDelete: false,//true:如果该队列没有任何订阅的消费者的话,该队列会被自动删除
arguments: null);//如果安装了队列优先级插件则可以设置优先级
string message = "Hello World!";//待发送的消息
var body = Encoding.UTF8.GetBytes(message);
channel.BasicPublish(exchange: "",//exchange名称
routingKey: "hello",//如果存在exchange,则消息被发送到名称为hello的queue的客户端
basicProperties: null,
body: body);//消息体
Console.WriteLine(" [x] Sent {0}", message);
}
Console.WriteLine(" Press [enter] to exit.");
Console.ReadLine();
}
}
好的,接下来启动程序,我们的消息就被推送到了Rabbit Server上的queue中,等待客户端的连接,也就是等待消费者拉取。如下图:
消费者
这次重新创建控制台应用程序,类名为Receive.cs,同理,你可以用自己舒服的单词去命名。
using RabbitMQ.Client;
using RabbitMQ.Client.Events;
using System;
using System.Text;
class Receive
{
public static void Main()
{
var factory = new ConnectionFactory() { HostName = "localhost" };
using(var connection = factory.CreateConnection())
using(var channel = connection.CreateModel())
{
channel.QueueDeclare(queue: "hello",//指定发送消息的queue,和生产者的queue匹配
durable: false,
exclusive: false,
autoDelete: false,
arguments: null);
var consumer = new EventingBasicConsumer(channel);
//注册接收事件,一旦创建连接就去拉取消息
consumer.Received += (model, ea) =>
{
var body = ea.Body;
var message = Encoding.UTF8.GetString(body);
Console.WriteLine(" [x] Received {0}", message);
};
channel.BasicConsume(queue: "hello",
noAck: true,//和tcp协议的ack一样,为false则服务端必须在收到客户端的回执(ack)后才能删除本条消息
consumer: consumer);
Console.WriteLine(" Press [enter] to exit.");
Console.ReadLine();
}
}
}
这段代码是不是和Send很相似呢,没错,在创建连接和声明queue上没有区别!
运行程序,效果如下:
哪怕你的Send程序已关闭,但只要运行过且成功发送了,queue就会一直保存消息,直到客户端连接,这些消息才会一股脑儿发送给消费者。
你可以这样实验,在bin中debug目录下启动Send.exe,连续3次,然后再运行客户端,就会收到3条消息,如下图:
至此,我们的Hello World已经成功跑起。这个小demo当然不是仅仅用来say hello的,更多的用意是帮助我理解兔子的基本原理,提供一种高并发情形下的解决方案。相信以后公司商城发展壮大时能够用到!!!
期待下一篇咯!