本系列文章均来自官网原文,属于个人翻译,如有雷同,权当个人归档,忽喷.
RabitMQ 是一个消息中间件,其实就是从消息生产者那里接受消息,然后发送给消息消费者.在这个传输过程中,可以定义一些缓存,持久化,路由的规则。
相关对象的术语简介:
1:生产者(producters)---发送消息的程序叫做生产者,使用带字母P的图来表示
2:队列(queue)--存储消息的邮箱名,存在于RabbitMQ内部,虽然消息流在RabbitMQ和应用程序之间流转,但消息存储的地方只能是队列,队列的绑定使用不受任何限制,它可以存储尽可能多的消息--事实上,它的缓冲大小是不受限制的。
许多生产者可以发送消息被路由到同一个队列,许多消费者也可以从一个队列接受消息,可以使用如下顶部带"queue_name"的图片表示.
3:消费者(consuming)--消费者比较类似接收者的概念,消费者实际上就是一个持续接受消息的程序,可以用带"C"的图片表示
"Hello Word"
在这个部分我们将会创建两个c#程序,一个消息生产者,一个消息接收者接收消息然后打印出来。我们将会掩盖一些.net Api的细节,关注非常简单的事情,"Hello Word"消息。
在下图当中"P"是我们的消息生产者,"C"是消息消费者,中间的部分是消息队列--RabbitMQ的消息缓冲组件
.Net 类库
RabbitMQ支持多种协议,在这个教程当中我们使用AMQP 0-9-1,一种开放的通用的消息协议,网上有许多客户端,这里我们使用RabbitMQ提供的.Net客户端。
发送
我们把消息生产者实现在Send.cs,消息接收实现在Receive.cs中,消息生产者连接RabbitMQ 服务器,发送一条简单的消息,然后退出。
class Send { public static void Main() { var factory = new ConnectionFactory() { HostName = "localhost" }; using (var connection = factory.CreateConnection()) { using (var channel = connection.CreateModel()) { ... } } } }
Connect连接抽象化了Socket 连接,而且为我们实现了协议握手认证等等,这里我们连接了一个localhost的代理,如果我们要连接在一个不同机器上的代理,我们可以简单的通过指定它的Ip或者name来实现。
然后我们创建了一个消息会话,我们所实现的大部分Api操作都要依赖于这个会话。
为了发送消息,我们需要创建一个队列来保存消息,然后发送消息。
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()) { channel.QueueDeclare(queue: "hello", durable: false, exclusive: false, autoDelete: false, arguments: null); string message = "Hello World!"; var body = Encoding.UTF8.GetBytes(message); channel.BasicPublish(exchange: "", routingKey: "hello", basicProperties: null, body: body); Console.WriteLine(" [x] Sent {0}", message); } Console.WriteLine(" Press [enter] to exit."); Console.ReadLine(); } }
声明的队列是幂等的--即只有当指定的队列不存在的时候才会创建,消息内容是一个此节数组,所以你可以使用你想用的任何编码。
当上面的代买运行过后,连接和会话将会释放。
发送不成功:
检查以下磁盘空间是否足够,默认限制的最小磁盘空间是50M,当小雨时,RabbitMQ代理将不会再接收新的消息。
配置文件将会给你展示怎么修改disk_free_limit
接收
消息被RabbitMQ推送到我们的接受者上面,所以不像消息生产者仅发送一条消息,我们的消息接收者持续监听消息队列,然后把他们打印出来。
我们打开一个连接和会话然后声明一个我们将要消费的目标消息队列,注意对应的就是生产者的队列。
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", durable: false, exclusive: false, autoDelete: false,arguments: null); ... } } } }
注意我们同样在这里也声明了消息队列,应为我们有可能先运行消息接收者,然后再运行消息生产者,我们必须要确认当我们消费一个队列时它是存在的。
我们告诉服务器把消息从队列当中发送给我们,因为服务器是异步把消息推送给我们的,所以我们提供了一个CallBack这个就是EventingBasicConsumer.Received 事件句柄。
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", 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, consumer: consumer); Console.WriteLine(" Press [enter] to exit."); Console.ReadLine(); } } }