• .NET中RabbitMq的使用


    【原文链接:https://www.cnblogs.com/xibei666/p/5931267.html

    .NET中RabbitMQ的使用

     

    概述

      MQ全称为Message Queue, 消息队列(MQ)是一种应用程序对应用程序的通信方法。RabbitMQ是一个在AMQP基础上完整的,可复用的企业消息系统。他遵循Mozilla Public License开源协议。AMQP(高级消息队列协议) 是一个异步消息传递所使用的应用层协议规范,作为线路层协议,而不是API(例如JMS),AMQP 客户端能够无视消息的来源任意发送和接受信息。AMQP的原始用途只是为金融界提供一个可以彼此协作的消息协议,而现在的目标则是为通用消息队列架构提供通用构建工具。因此,面向消息的中间件 (MOM)系统,例如发布/订阅队列,没有作为基本元素实现。AMQP当中有四个概念非常重要(一个虚拟主机持有一组交换机、队列和绑定):

    1. virtual host,虚拟主机
    2. exchange,交换机
    3. queue,队列
    4. binding,绑定

      更多理论性东西可以参考(在Windows上安装Rabbit MQ 指南),针对队列的讲解相当详细

    Window下安装RabbbitMQ

    文件下载安装

    Rabbit MQ 是建立在强大的Erlang OTP平台上,因此安装Rabbit MQ的前提是安装Erlang。通过下面两个连接下载安装3.2.3 版本:

    1. 下载并安装 Erlang OTP For Windows (vR16B03)
    2. 运行安装 Rabbit MQ Server Windows Installer (v3.2.3)

    默认安装的Rabbit MQ 监听端口是5672。先安装Erlang OTP后安装RabbitMQ,安装方式默认即可,RabbitMQ可以勾选安装后台服务、服务启动和停止等操作。

    激活Rabbit MQ's Management Plugin

    使用Rabbit MQ 管理插件,可以更好的可视化方式查看Rabbit MQ 服务器实例的状态,打开CMD命令,cd到安装目录(.. abbitmq_server-3.2.3sbin)下,输入下面的命令激活:

    rabbitmq-plugins enable rabbitmq_management

    要重启服务才能生效,可以执行

    net stop RabbitMQ && net start RabbitMQ

    输入网址,打开监控页面:  http://localhost:15672 (默认账号和密码:guest 和guest)

    配置RabbitMQ用户权限

    RabbitMQ是存在用户权限的,默认是guest 密码也是guest,隶属于Administrator管理员下。现需要配置新用户和权限,继续打开CMD命令,cd到安装目录sbin下:

    用户操作指令:

    复制代码
    ::查询服务状态
    rabbitmqctl status

    ::列举虚拟主机列表
    rabbitmqctl list_vhosts
    ::列举用户列表
    rabbitmqctl list_users

    :: 添加用户和密码 rabbitmqctl add_user hao abc123 :: 设置权限 rabbitmqctl set_permissions yy
    ".*" ".*" ".*" :: 分配用户组 rabbitmqctl set_user_tags yy administrator
    :: 删除guest用户
    rabbitmqctl delete_user guest
    ::修改用户密码
    rabbitmqctl change_password {username}  {newpassowrd}
    复制代码

    .NET中RabbitMQ使用

    1、Nuget下载RabbitMQ.Client第三方类库,版本V3.6.5,高版本与.NET Framework 4.5有冲突,RabbitMQ Client地址

    2、利用RabbitMQ Clinet类库编码(代码内容有注释,此处不做详细解释,文章后有完整代码的下载地址)

      <1>RabbitMQ的direct类型Exchange

       Producter发送消息代码:

    复制代码
            /// <summary>
            /// 连接配置
            /// </summary>
            private static readonly ConnectionFactory rabbitMqFactory = new ConnectionFactory(){
                HostName ="192.168.1.8",UserName="hao",Password="abc123",Port= 5672
            };
            /// <summary>
            /// 路由名称
            /// </summary>
            const string ExchangeName = "justin.exchange";
    
            //队列名称
            const string QueueName = "justin.queue";
            public static void DirectExchangeSendMsg()
            {
                using (IConnection conn = rabbitMqFactory.CreateConnection())
                {
                    using (IModel channel = conn.CreateModel())
                    {
                        channel.ExchangeDeclare(ExchangeName, "direct", durable: true, autoDelete: false, arguments: null);
                        channel.QueueDeclare(QueueName, durable: true, autoDelete: false, exclusive: false, arguments: null);
                        channel.QueueBind(QueueName, ExchangeName, routingKey: QueueName);
    
                        var props = channel.CreateBasicProperties();
                        props.Persistent = true;
                        string vadata = Console.ReadLine();
                        while (vadata != "exit")
                        {
                            var msgBody = Encoding.UTF8.GetBytes(vadata);
                            channel.BasicPublish(exchange: ExchangeName, routingKey: QueueName, basicProperties: props, body: msgBody);        
                            Console.WriteLine(string.Format("***发送时间:{0},发送完成,输入exit退出消息发送",DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")));
                            vadata = Console.ReadLine();
                        }                   
                    }
                }
            }
    复制代码

       

      Customer接收消息代码:

    复制代码
            /// <summary>
            /// 连接配置
            /// </summary>
            private static readonly ConnectionFactory rabbitMqFactory = new ConnectionFactory() {
                HostName = "192.168.1.8", UserName = "hao", Password = "abc123", Port = 5672
            };
            /// <summary>
            /// 路由名称
            /// </summary>
            const string ExchangeName = "justin.exchange";
    
            //队列名称
            const string QueueName = "justin.queue";
            public static void DirectAcceptExchange()
            {
                using (IConnection conn = rabbitMqFactory.CreateConnection())
                {
                    using (IModel channel = conn.CreateModel())
                    {
                        channel.ExchangeDeclare(ExchangeName, "direct", durable: true, autoDelete: false, arguments: null);
                        channel.QueueDeclare(QueueName, durable: true, autoDelete: false, exclusive: false, arguments: null);
                        channel.QueueBind(QueueName, ExchangeName, routingKey: QueueName);
                        while (true)
                        { 
                            BasicGetResult msgResponse = channel.BasicGet(QueueName, noAck: true);
                            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));
                            }
    
                            //BasicGetResult msgResponse2 = channel.BasicGet(QueueName, noAck: false);
    
                            ////process message ...
    
                            //channel.BasicAck(msgResponse2.DeliveryTag, multiple: false);
                            System.Threading.Thread.Sleep(TimeSpan.FromSeconds(1));
                        }
                    }
                }
            }
    复制代码

      

      但是这种处理速度较慢,因为循环线程等待。高效的接收消息的方式可以使用EventingBasicConsumer进行消息接收处理,修改代码内容如下:

    复制代码
            public static void DirectAcceptExchangeEvent()
            {
                using (IConnection conn = rabbitMqFactory.CreateConnection())
                {
                    using (IModel channel = conn.CreateModel())
                    {
                        //channel.ExchangeDeclare(ExchangeName, "direct", durable: true, autoDelete: false, arguments: null);
                        channel.QueueDeclare(QueueName, durable: true, autoDelete: false, exclusive: false, arguments: null);
                        //channel.QueueBind(QueueName, ExchangeName, routingKey: QueueName);
                        var consumer = new EventingBasicConsumer(channel);
                        consumer.Received += (model, ea) =>
                        {                        
                            var msgBody = Encoding.UTF8.GetString(ea.Body);
                            Console.WriteLine(string.Format("***接收时间:{0},消息内容:{1}", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"), msgBody));
                        };
                        channel.BasicConsume(QueueName, noAck: true, consumer: consumer);
    
                        //已过时用EventingBasicConsumer代替
                        //var consumer2 = new QueueingBasicConsumer(channel);
                        //channel.BasicConsume(QueueName, noAck: true, consumer: consumer);
                        //var msgResponse = consumer2.Queue.Dequeue(); //blocking
                        //var msgBody2 = Encoding.UTF8.GetString(msgResponse.Body);
    
                        Console.WriteLine("按任意值,退出程序");
                        Console.ReadKey();
                    }
                }
            }
    复制代码

      

      但是有些时候,消费者同一时间没有能力处理太多的业务,导致分配过来的队列消息不能及时处理完成,这个时候,我们可以设置BasicQos属性,告诉Broker同一时间将未处理完成的消息分配其他消费者,所以接收消息的地方需要略做修改,代码如下:

    复制代码
    public static void DirectAcceptExchangeTask()
    {
        using (IConnection conn = rabbitMqFactory.CreateConnection())
        {
            using (IModel channel = conn.CreateModel())
            {
                //channel.ExchangeDeclare(ExchangeName, "direct", durable: true, autoDelete: false, arguments: null);
                channel.QueueDeclare(QueueName, durable: true, autoDelete: false, exclusive: false, arguments: null);
                channel.BasicQos(prefetchSize: 0, prefetchCount: 1, global: false);//告诉broker同一时间只处理一个消息
                //channel.QueueBind(QueueName, ExchangeName, routingKey: QueueName);
                var consumer = new EventingBasicConsumer(channel);
                consumer.Received += (model, ea) =>
                {
                    var msgBody = Encoding.UTF8.GetString(ea.Body);
                    Console.WriteLine(string.Format("***接收时间:{0},消息内容:{1}", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"), msgBody));
                    int dots = msgBody.Split('.').Length - 1;
                    System.Threading.Thread.Sleep(dots * 1000);
                    Console.WriteLine(" [x] Done");
                    //处理完成,告诉Broker可以服务端可以删除消息,分配新的消息过来
                    channel.BasicAck(deliveryTag: ea.DeliveryTag, multiple: false);
                };
                //noAck设置false,告诉broker,发送消息之后,消息暂时不要删除,等消费者处理完成再说
                channel.BasicConsume(QueueName, noAck: false, consumer: consumer);
    
                Console.WriteLine("按任意值,退出程序");
                Console.ReadKey();
            }
        }
    }
    复制代码

      

      <2> RabbitMQ的Topic类型Exchange

      Producter 发送消息代码:

    复制代码
            /// <summary>
            /// 连接配置
            /// </summary>
            private static readonly ConnectionFactory rabbitMqFactory = new ConnectionFactory(){
                HostName ="192.168.1.8",UserName="hao",Password="abc123",Port= 5672
            };
            /// <summary>
            /// 路由名称
            /// </summary>
            const string TopExchangeName = "topic.justin.exchange";
    
            //队列名称
            const string TopQueueName = "topic.justin.queue";
    
            public static void TopicExchangeSendMsg()
            {
                using (IConnection conn = rabbitMqFactory.CreateConnection())
                {
                    using (IModel channel = conn.CreateModel())
                    {
                        channel.ExchangeDeclare(TopExchangeName, "topic", durable: false, autoDelete: false, arguments: null);
                        channel.QueueDeclare(TopQueueName, durable: false, autoDelete: false, exclusive: false, arguments: null);
                        channel.QueueBind(TopQueueName, TopExchangeName, routingKey: TopQueueName);
                        //var props = channel.CreateBasicProperties();
                        //props.Persistent = true;
                        string vadata = Console.ReadLine();
                        while (vadata != "exit")
                        {
                            var msgBody = Encoding.UTF8.GetBytes(vadata);
                            channel.BasicPublish(exchange: TopExchangeName, routingKey: TopQueueName, basicProperties: null, body: msgBody);
                            Console.WriteLine(string.Format("***发送时间:{0},发送完成,输入exit退出消息发送", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")));
                            vadata = Console.ReadLine();
                        }
                    }
                }
            }
    复制代码

      Customer接收消息代码:

    复制代码
            /// <summary>
            /// 连接配置
            /// </summary>
            private static readonly ConnectionFactory rabbitMqFactory = new ConnectionFactory() {
                HostName = "192.168.1.8", UserName = "hao", Password = "abc123", Port = 5672
            };
    
            /// <summary>
            /// 路由名称
            /// </summary>
            const string TopExchangeName = "topic.justin.exchange";
    
            //队列名称
            const string TopQueueName = "topic.justin.queue";
    
            public static void TopicAcceptExchange()
            {
                using (IConnection conn = rabbitMqFactory.CreateConnection())
                {
                    using (IModel channel = conn.CreateModel())
                    {
                        channel.ExchangeDeclare(TopExchangeName, "topic", durable: false, autoDelete: false, arguments: null);
                        channel.QueueDeclare(TopQueueName, durable: false, autoDelete: false, exclusive: false, arguments: null);
                        channel.BasicQos(prefetchSize: 0, prefetchCount: 1, global: false);
                        channel.QueueBind(TopQueueName, TopExchangeName, routingKey: TopQueueName);
                        var consumer = new EventingBasicConsumer(channel);
                        consumer.Received += (model, ea) =>
                        {
                            var msgBody = Encoding.UTF8.GetString(ea.Body);
                            Console.WriteLine(string.Format("***接收时间:{0},消息内容:{1}", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"), msgBody));
                            int dots = msgBody.Split('.').Length - 1;
                            System.Threading.Thread.Sleep(dots * 1000);
                            Console.WriteLine(" [x] Done");
                            channel.BasicAck(deliveryTag: ea.DeliveryTag, multiple: false);
                        };
                        channel.BasicConsume(TopQueueName, noAck: false, consumer: consumer);
    
                        Console.WriteLine("按任意值,退出程序");
                        Console.ReadKey();
                    }
                }
            }
    复制代码

    参考资料:

    在 Windows 上安装Rabbit MQ 指南(http://www.cnblogs.com/shanyou/p/4067250.html)

    .NET 环境中使用RabbitMQ(http://www.cnblogs.com/yangecnu/p/4227535.html)

    RabbitMQ Tutorial(http://www.rabbitmq.com/tutorials/tutorial-six-dotnet.html)

    源代码下载

    知道的越多,不知道的也就越多,多多学习!

  • 相关阅读:
    微信小程序 单选按钮 最佳
    微信小程序 单选按钮的实现
    微信小程序 单选框实现
    Java Code To Create Pyramid and Pattern
    Java language
    npm Err! Unexpected end of JSON input while parsing near
    Node.js Express FrameWork Tutorial
    Higher-Order Function Examples
    Create First HTTP Web Server in Node.js: Complete Tutorial
    Node.js NPM Tutorial: Create, Publish, Extend & Manage
  • 原文地址:https://www.cnblogs.com/Mask71/p/13752220.html
Copyright © 2020-2023  润新知