Net中使用 RabbitMq | Topic ExChange 模糊路由模式(主題模式)

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));
                        }                      
                    }
                }
            }
        }
    }
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章