一、定义:

MQ是MessageQueue,消息队列的简称(是流行的开源消息队列系统,利用erlang语言开发)。MQ是一种应用程序对应用程序的通信方法。应用程序通过读写入队和出队的消息来通信,无需专用连接来链接它们。

消息传递是程序之间通过在消息中发送数据进行通信,而不是通过直接调用彼此来通信,一般应用于远程过程调用的技术。

排队指的是应用程序通过队列来通信。应用队列避免接收和发送数据的同时进行。

二、特点:

MQ是消费者-生产者模型的代表。一端往消息队列中写入消息,另一端可以读取或者订阅队列中的消息。MQ遵循的是AMQP协议(高级消息队列协议:使得遵从该规范的客户端应用和消息中间件服务器的全功能互操作成为可能)的具体实现和产品。

三、应用:

在使用MQ时,我们不需要实时的返回信息。获取信息和返回信息进行异步处理。例如:在项目中,我们需要从汽车系统中利用CAN总线实时的获取汽车的相关信息,但是没有必要给汽车返回信息。如,获取汽车的轮胎气压,但是我们不需要给汽车一个返回的信息或结果。

C#项目要利用RabbitMQ来获取实时数据的话,需要先安装客户端的库文件:RabbitMQ.Client.dll,下载地址如下:

http://download.csdn.net/detail/qq_30507287/9599941

四、RabbitMQ的结构图:

五、基本概念:

Broker:消息队列服务器实体。

Exchange:消息交换机,指定消息按照什么规则,路由到哪个队列。可以理解成具有路由表的程序。每个消息都有一个成为路由键(routing key)的属性。交换机中有一系列的绑定(binding)即路由规则。

Queue:消息队列载体,每个消息都会被投入到一个或多个队列。消息一直在里面,直到有客户端(消费者)连接到这个队列并且将其取走为止。队列是有消费者通过程序建立的。

Binding:绑定,作用:把exchange和queue按照路由规则绑定起来。

Routing Key:路由关键字,exchange根据这个关键字进行消息投递。

Vhost(virtualhost):虚拟主机,一个broker里可以开设多个vhost,用作不同用户的权限分离。

producer:消息生产者,就是投递消息的程序。

consumer:消息消费者,就是接受消息的程序。

channel:消息通道,在客户端的每个连接里,可建立多个channel,每个channel代表一个会话任务。

注1:比较重要的四个:vhost,exchange,queue,binding。一个虚拟主机持有一组交换机、队列和绑定。

注2:消费者程序要负责创建交换机们(不止一个)?因为每个交换机在自己独立的进程当中执行,增加多个交换机就是增加多个进程,可以充分利用服务器上的CPU的核来提高效率。(一个8核服务上,可以用5核来创建5个交换机,剩余的3个用来处理消息。)

注3:一个绑定(binding)就是一个基于路由键将交换机和队列连接起来的路由规则。

六、消息队列的使用过程大概如下:

(1)客户端连接到消息队列服务器,打开一个channel。

(2)客户端声明一个exchange,并设置相关属性。

(3)客户端声明一个queue,并设置相关属性。

(4)客户端使用routingkey,在exchange和queue之间建立好绑定关系。

(5)客户端投递消息到exchange。

说明:exchange接收到消息后,就根据消息的key和已经设置的binding,进行消息路由,将消息投递到一个或多个队列里。

七、Exchange(交换机的类型)的类型:

1)Direct交换机:

(处理路由键)完全根据key进行投递。需要将一个队列绑定到交换机上,要求该消息与一个特定的路由键完全匹配。

绑定时设置了routing key为“abc”,那么客户端提交的消息,只有设置了key为“abc”的才会投递到队列。

2)Topic交换机:

(将路由键和某模式进行匹配)此时队列需要绑定到一个模式上,对key进行模式匹配后进行投递。

“#”匹配一个或多个词,“*”匹配正好一个词。“abc.#”匹配“abc.def.ghi”,“abc.*”只匹配“abc.def”。

3)Fanout交换机:(不处理路由键)不需要key值,采用广播模式,消息进来时,投递到与该交换机绑定的所有队列。

八、队列消息的持久化:

1、为什么会有持久化?

花费大量时间来创建队列,交换机和绑定,如果服务器出现意外或外界故障,那么队列,交换机和绑定就会清空。RabbitMQ重启之后就会清空原来的东西。因此在创建队列和交换机时就会指定一个标志durable来控制。当然,durable表示的含义:含有该标志的队列和交换机在重启之后会重新建立,而不是,在队列中的消息会重启后恢复。

2、消息队列持久化包括3个部分:

(1)exchange持久化,在声明时指定durable => 1;

(2)queue持久化,在声明时指定durable => 1;

(3)消息持久化,在投递时指定delivery_mode=> 2(1是非持久化,2表示persistent,持久化);

如果exchange和queue都是持久化的,那么它们之间的binding也是持久化的。如果exchange和queue两者之间有一个持久化,一个非持久化,就不允许建立绑定。

说明:delivery mode(投递模式)

3、绑定(binding)的持久化:

绑定在创建的时候无法设置durable,那么绑定的持久化是靠队列和交换机来实现的。如果绑定一个durable的队列和一个durable的交换机,RabbitMQ会自动保留这个绑定。只要队列和交换机之一不是durable,那么依赖它们的绑定就会自动删除。

九、.NET/C#客户端中的RabbitMQ

(1)主要的命名空间,接口和类

核心的API接口和类都定义在命名空间为RabbitMQ.Client中。

using RabbitMQ.Client;

核心的接口和类是:

IModel: representsan AMQP 0-9-1 channel, and provides most of the operations (protocol methods).代表通道,提供协议方法。

IConnection:represents an AMQP 0-9-1 connection

ConnectionFactory:constructs IConnection instances

IBasicConsumer:represents a message consumer表示消息的消费者。

其他的接口和类:

DefaultBasicConsumer:commonly used base class for consumers

其他公共的RabbitMQ.Client命名空间还包括:

RabbitMQ.Client.Events:various events and event handlers that are part of the client library,including EventingBasicConsumer, a consumer implementation built around C#event handlers.

RabbitMQ.Client.Exceptions:exceptions visible to the user.

(2)连接代理

连接到RabbitMQ,必须要实例化一个ConnectionFactory和configure一个RabbitMQ到主机,虚拟机或认证的设备上。下面的代码是在主机上连接RabbitMQ结点。

ConnectionFactory factory = newConnectionFactory();

factory.Uri = "amqp://user:pass@hostName:port/vhost";

IConnection conn = factory.CreateConnection();

然后用iconnection接口可以用来打开一个通道:

IModel channel = conn.CreateModel();

(3)使用交换机和队列

model.ExchangeDeclare(exchangeName,ExchangeType.Direct);

model.QueueDeclare(queueName,false,false,false,null);

model.QueueBind(queueName, exchangeName, routingKey,null);

(4)发布消息

利用交换机(exchange)发送消息,使用的是IModel.BasicPublish

byte[]messageBodyBytes = System.Text.Encoding.UTF8.GetBytes("Hello, world!");

model.BasicPublish(exchangeName, routingKey,null,messageBodyBytes);

对于细节,可以用重载变量来指定标志或特殊的消息属性:

byte[]messageBodyBytes = System.Text.Encoding.UTF8.GetBytes("Hello, world!");

IBasicProperties props = model.CreateBasicProperties();

props.ContentType = "text/plain";

props.DeliveryMode = 2;

model.BasicPublish(exchangeName,routingKey, props, messageBodyBytes);

发送自定义的消息:

byte[]messageBodyBytes = System.Text.Encoding.UTF8.GetBytes("Hello, world!");

IBasicProperties props = model.CreateBasicProperties();

props.ContentType = "text/plain";

props.DeliveryMode = 2;

props.Headers = new Dictionary<string,object>();

props.Headers.Add("latitude",  51.5252949);

props.Headers.Add("longitude",-0.0905493);

model.BasicPublish(exchangeName, routingKey, props, messageBodyBytes);

十、(C#实例解析)生产者应用程序解析

(1)从生产者应用程序来看,建立一个使用默认设置的连接,创建连接并创建一个通道:

namespaceProducer
{
classProgram
{
staticvoidMain(string[] args)
{
var connectionFactory =newConnectionFactory();
IConnection connection =connectionFactory.CreateConnection();
IModel channel = connection.CreateModel();
}
}
}

  

(2)声明一个交换机并发布消息

channel.ExchangeDeclare("direct-exchange-example",ExchangeType.Direct);

第二个参数表名了参数的类型,可以选择direct,fanout,topic,或者headers。

(3)调用方法,产生一个返回值,本例中调用的是DoSomethingInteresting(),并且返回一个字符串的值。

string value = DoSomethingInteresting();

(4)dosomethinginteresting()实施可以返回一个新的GUID字符串值

staticstringDoSomethingInteresting()

{

returnGuid.NewGuid().ToString();

}

(5)利用返回值来创建一个日志消息:

string logMessage =string.Format("{0}: {1}", TraceEventType.Information, value);

(6)将日志消息转换为字节数组,并将消息发布到新的交换机上:

byte[]message =Encoding.UTF8.GetBytes(logMessage);

channel.BasicPublish("direct-exchange-example","",null,message);

(7)最后,要关闭通道和连接

channel.Close();

connection.Close();

十一、(C#实例解析)消费者应用程序解析

(1)和生成者一样创建消费者

using RabbitMQ.Client;

namespace Consumer
{
classProgram
{
staticvoidMain(string[] args)
{
varconnectionFactory = new ConnectionFactory();
IConnection connection = connectionFactory.CreateConnection();
IModel channel = connection.CreateModel(); channel.ExchangeDeclare("direct-exchange-example",ExchangeType.Direct);
}
}
}

  

(2)声明一个队列去绑定交换机,队列的名字为“logs”

channel.QueueDeclare("logs",false,false,true,null);

(3)绑定“logs”队列,利用QueueBind()

channel.QueueBind("logs","direct-exchange-example","");

(4)声明消费者对象

var consumer =newQueueingBasicConsumer(channel)

(5)推送消息

channel.BasicConsume(“logs”, true,consumer);

(6)任何消息都将被自动检索,并放置在内存队列的本地内存队列中。

var eventArgs =(BasicDeliverEventArgs)consumer.Queue.Dequeue();

将eventArgs转换成字符串并打印输出

var message =Encoding.UTF8.GetString(eventArgs.Body);

Console.WriteLine(message);

(7)关闭通道和连接

channel.Close();

connection.Close();

十二、(C#实例代码)生产-消费模式的完整代码

(1)

using System;
using System.Diagnostics;
using System.Text;
using System.Threading;
using RabbitMQ.Client; namespace Producer
{
classProgram
{
staticvoidMain(string[] args)
{
Thread.Sleep(1000);
varconnectionFactory = new ConnectionFactory();
IConnection connection = connectionFactory.CreateConnection();
IModel channel = connection.CreateModel(); channel.ExchangeDeclare("direct-exchange-example",ExchangeType.Direct);
stringvalue = DoSomethingInteresting();
stringlogMessage = string.Format("{0}:{1}",TraceEventType.Information,value); byte[]message = Encoding.UTF8.GetBytes(logMessage);
channel.BasicPublish("direct-exchange-example","",null,message); channel.Close();
connection.Close();
} staticstringDoSomethingInteresting()
{
returnGuid.NewGuid().ToString();
}
}
}

  (2)

using System;
using System.Text;
using RabbitMQ.Client;
using RabbitMQ.Client.Events; namespace Consumer
{
classProgram
{
staticvoidMain(string[] args)
{
varconnectionFactory = new ConnectionFactory();
IConnection connection = connectionFactory.CreateConnection();
IModel channel = connection.CreateModel(); channel.ExchangeDeclare("direct-exchange-example",ExchangeType.Direct);
channel.QueueDeclare("logs",false,false,true,null);
channel.QueueBind("logs","direct-exchange-example",""); varconsumer = new QueueingBasicConsumer(channel);
channel.BasicConsume("logs",true,consumer); vareventArgs = (BasicDeliverEventArgs)consumer.Queue.Dequeue(); stringmessage = Encoding.UTF8.GetString(eventArgs.Body);
Console.WriteLine(message); channel.Close();
connection.Close();
Console.ReadLine();
}
}
}

  转载:

    http://blog.csdn.net/qq_30507287/article/details/52176603

RabbitMQ基础学习笔记(C#代码示例)的更多相关文章

  1. C#RabbitMQ基础学习笔记

    RabbitMQ基础学习笔记(C#代码示例) 一.定义: MQ是MessageQueue,消息队列的简称(是流行的开源消息队列系统,利用erlang语言开发).MQ是一种应用程序对应用程序的通信方法. ...

  2. 尚学堂JAVA基础学习笔记

    目录 尚学堂JAVA基础学习笔记 写在前面 第1章 JAVA入门 第2章 数据类型和运算符 第3章 控制语句 第4章 Java面向对象基础 1. 面向对象基础 2. 面向对象的内存分析 3. 构造方法 ...

  3. 【C#编程基础学习笔记】4---Convert类型转换

    2013/7/24 技术qq交流群:JavaDream:251572072  教程下载,在线交流:创梦IT社区:www.credream.com [C#编程基础学习笔记]4---Convert类型转换 ...

  4. 1.C#基础学习笔记3---C#字符串(转义符和内存存储无关)

    技术qq交流群:JavaDream:251572072  教程下载,在线交流:创梦IT社区:www.credream.com ------------------------------------- ...

  5. Java基础学习笔记(一)

    Java基础学习笔记(一) Hello World 基础代码学习 代码编写基础结构 class :类,一个类即一个java代码,形成一个class文件,写于每个代码的前端(注意无大写字母) XxxYy ...

  6. handlebars.js基础学习笔记

    最近在帮学校做个课程网站,就有人推荐用jquery+ajax+handlebars做网站前端,刚接触发现挺高大上的,于是就把一些基础学习笔记记录下来啦. 1.引用文件: jquery.js文件下载:h ...

  7. 基础学习笔记之opencv(6):实现将图片生成视频

    基础学习笔记之opencv(6):实现将图片生成视频 在做实验的过程中.难免会读视频中的图片用来处理,相反将处理好的图片又整理输出为一个视频文件也是非经常常使用的. 以下就来讲讲基于opencv的C+ ...

  8. Oracle基础学习笔记

    Oracle基础学习笔记 最近找到一份实习工作,有点头疼的是,有阶段性考核,这...,实际想想看,大学期间只学过数据库原理,并没有针对某一数据库管理系统而系统的学习,这正好是一个机会,于是乎用了三天时 ...

  9. C++基础 学习笔记之一:源代码的格式化

    C++基础 学习笔记之一:源代码的格式化 1. 源代码中的标记与空白 C++中的语句是以分号表示语句的结束.在C++中空格和回车以及制表符均为相同作用,即三者通常可以互相替代. 例如可以将一个简单的m ...

随机推荐

  1. vsftp进阶-锁定目录

    把用户锁定到特定的目录下面: 一.配置文件: #grep -Ev "^#|^$" /etc/vsftpd/vsftpd.conf anonymous_enable=NOlocal_ ...

  2. 将数据库返回的ResultSett转换成List装Map形式的方法(ResultSetToList)

    多时候想做一些关于数据库实验,如果先搭建框架太麻烦,直接得到ResultSet处理起来取值什么的也很繁琐,为此我做了一个将ResultSet转换成List<Map<String,Objec ...

  3. PhotoZoom Pro 7怎么进行参数设置

    每个用户在使用PhotoZoom时,在针对不同的图片,我们处理的方式也不同.所以在参数设置会因图片不同而不同.那么在PhotoZoom中参数究竟如何设置呢? 首先,我们先打开[参数设置],点击后会弹出 ...

  4. switch 语句来选择要执行的多个代码块之一。

    switch(n) { case 1: 执行代码块 1 break; case 2: 执行代码块 2 break; default: n 与 case 1 和 case 2 不同时执行的代码 }

  5. Python基础:编码

    1:先说python2py2里默认编码是ascii文件开头那个编码声明是告诉解释这个代码的程序 以什么编码格式 把这段代码读入到内存,因为到了内存里,这段代码其实是以bytes二进制格式存的,不过即使 ...

  6. Laravel5.6安裝:Warning: require(../vendor/autoload.php): failed to open stream: No such file or directory

    在phpstudy下使用composer+laravel安装器的方式安装了Laravel,但是访问的时候报错: Warning: require(D:\phpstudy\WWW\public\mybl ...

  7. 路飞学城Python-Day186

    Evernote Export 持续集成 持续集成,简单的说就是持续集成频繁的将代码集成到主干,它的好处主要有1.快速发现错误,没完成一点更新,就集成到主干,可以快速发现错误,定位错误也会比较容易,2 ...

  8. 训练1-K

    一个整数,只知道前几位,不知道末二位,被另一个整数除尽了,那么该数的末二位该是什么呢? Input 输入数据有若干组,每组数据包含二个整数a,b(0<a<10000, 10<b< ...

  9. [CodeForces]786B Legacy

    线段树优化建图. 建立两棵线段树,其上点的点权分别表示"到达这个区间内所有点的最小花费"和"到达这个区间内任意一个点的最小花费". 对于第一种路直接加边即可 对 ...

  10. 深入了解Spring中的容器

    1.创建Bean的3种方式 1.1使用构造器创建bean实例 这是最常见的方式,如果不采用构造注入,bean类需要有默认构造函数.如果采用构造注入,则需要配置xml文件的<constructor ...