標籤:read ogr 發送訊息 代碼 highlight content rect nbsp bin
一、定義:
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:[email protected]: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#程式碼範例)