RabbitMQ提供了四種Exchange:direct, topic, fanout, header
header模式在實際使用中較少,本文只對前三種模式進行比較。
Topic ExChange屬於模糊連接模式(主題模式),
直連模式就是 Exchange 通過 指定的RoutingKey 將 消息轉發到與之綁定的Queue中
注:可以這樣理解:生產者想發送一條消息到指定的Queue隊列中,首先這條消息會Exchange接收到,因爲Exchange與queue是進行了綁定,這個綁定指定了RoutingKey(路由名稱),這時候Exchange就會通過這個路由名稱,來找到指定的Queue,然後將消息保存到Queue中 這就是直連模式
注:當一個Exchange與Queue進行綁定的時候,不是一定要指定RoutingKey的,比如Fanout 模式下就不需要指定RoutingKey
Topic ExChange與Direct ExChange不同點是在於,Topic ExChange可以模糊匹配RoutingKey(路由)來將數據轉發到與之綁定的Queue中,而Direct ExChange則是需要完全匹配RoutingKey(路由)才轉發。
Topic模式下 必須先啓動消費者端,然後再生產者端。
ProducterApp:生產者端
注意:在Topic模型下,生產者段不需要創建Queue 自然也不需要設定Queue與Exchange綁定
using RabbitMQ.Client;
using System.Text;
namespace ProducterApp
{
class Program
{
/// 連接配置
/// </summary>
private static readonly ConnectionFactory rabbitMqFactory = new ConnectionFactory() //創建一個工廠連接對象
{
HostName = "192.168.31.30",
UserName = "admin",
Password = "admin",
VirtualHost = "/vhost001", //如果不設置,虛擬主機名稱路徑默認爲 /
Port = 5672, //注意:5672 --是client端通信口 15672 -- 是管理界面ui端口
};
/// <summary>
/// 路由名稱
/// </summary>
const string ExchangeName = "exchange002";
static void Main(string[] args)
{
using (IConnection conn = rabbitMqFactory.CreateConnection()) //創建一個連接
{
using (IModel channel = conn.CreateModel()) //創建一個Channel
{
//注意:在Topic模型下,生產者段不需要創建Queue 自然也不需要設定Queue與Exchange綁定
//Exchange的Type類型有:direct,topic, fanout,headers
//direct:所有發送到Direct Exchange的消息都會被轉發到RouteKey中指定的Queue;當消費者要消費這個Queue中的消息都會時候它要求消費者的RoutingKey與生產者的RoutingKey完全匹配
//topic:所有發送到Topic Exchange的消息都會轉發到所有關心的RoutingKey
//durable是Exchange(交換機)的屬性,它表示是否需要持久化,爲true則爲持久化。false表示不需要持久化
//autoDelete:它是Exchange(交換機)的屬性,它的值有true和false兩種
//爲true 則表示當最後一個綁定到Exchange(交換機)上的Queue(隊列)刪除後,就自動刪除該Exchange
//這段話也很好理解,假如Exchange(交換機)上綁定了三個Queue(隊列),當這個三個Queue(隊列)都被刪除的時候這個Exchange(交換機)將會被自動刪除
//arguments:它是擴展參數,用於擴展AMQP協議自制定化的使用
channel.ExchangeDeclare(ExchangeName, "topic", durable: false, autoDelete: false, arguments: null); //聲明一個Exchange(交換機)
string routingKey1 = "user.america";//這個routingKey的值可以隨便你自己設置
string routingKey2 = "user.china";
string routingKey3 = "user.china.beijing";
var props = channel.CreateBasicProperties();
props.Persistent = true;
for (int i = 0; i < 5; i++)
{
//發送的消息必須是二進制的
channel.BasicPublish(exchange: ExchangeName, routingKey: routingKey1, basicProperties: props, body: Encoding.UTF8.GetBytes("你好美國,這是我的第" + i + "條消息"));
channel.BasicPublish(exchange: ExchangeName, routingKey: routingKey2, basicProperties: props, body: Encoding.UTF8.GetBytes("你好中國,這是我的第" + i + "條消息"));
channel.BasicPublish(exchange: ExchangeName, routingKey: routingKey3, basicProperties: props, body: Encoding.UTF8.GetBytes("你好中國北京,這是我的第" + i + "條消息"));
}
}
}
}
}
}
CustomerApp:消費者端
using RabbitMQ.Client;
using System;
using System.Text;
namespace CustomerApp
{
class Program
{
/// <summary>
/// 連接配置
/// </summary>
private static readonly ConnectionFactory rabbitMqFactory = new ConnectionFactory()
{
HostName = "192.168.31.30",
UserName = "admin",
Password = "admin",
Port = 5672,
VirtualHost = "/vhost001",
};
/// <summary>
/// 路由名稱
/// </summary>
const string ExchangeName = "exchange002";
//隊列名稱
const string QueueName = "queue002";
static void Main(string[] args)
{
using (IConnection conn = rabbitMqFactory.CreateConnection())
{
using (IModel channel = conn.CreateModel())
{
//創建交換機這裏將Exchange(交換機)Type設定爲topic 【消費者端的交換機名稱要與生產者端的交換機名稱保持一致】
channel.ExchangeDeclare(ExchangeName, "topic", durable: false, autoDelete: false, arguments: null);
//創建隊列【消費者端需要創建隊列,生產者端不需要創建隊列】
channel.QueueDeclare(QueueName, durable: true, autoDelete: false, exclusive: false, arguments: null);
//如果生產者端的交換機通過 user.america,user.china,user.china.beijing 這三條RoutingKey來發送消息
//那麼"user.#" 那麼消費者端就只能接受到生產者端生產者通過user.america和user.china這兩條RoutingKey發送過來的消息
//如果消費者端的RoutingKey改成user.# 那麼消費者端可以接受到生產者端生產者通過user.america和user.china和user.china.beijing這三條RoutingKey發送過來的所有消息
string routingKey = "user.*";
channel.QueueBind(QueueName, ExchangeName, routingKey: routingKey);
while (true)
{
//System.Threading.Thread.Sleep(TimeSpan.FromSeconds(5));
BasicGetResult msgResponse = channel.BasicGet(QueueName, autoAck: true);//這個true表示消費完這條數據是否刪除,true表示刪除,false表示不刪除
if (msgResponse != null)
{
var msgBody = Encoding.UTF8.GetString(msgResponse.Body);
Console.WriteLine(string.Format("接收時間:{0},消息內容:{1}", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"), msgBody));
}
}
}
}
}
}
}