net core 使用 rabbitmq

windows环境安装:
https://www.cnblogs.com/ericli-ericli/p/5902270.html
.NET Core 使用RabbitMQ
https://www.cnblogs.com/stulzq/p/7551819.html

安装

"C:\Program Files\RabbitMQ Server\rabbitmq_server-3.7.9\sbin\rabbitmq-plugins.bat" enable rabbitmq_management

net stop RabbitMQ && net start RabbitMQ

创建用户,密码,绑定角色

查看已有用户及用户的角色:
rabbitmqctl.bat list_users

新增一个用户:
rabbitmqctl.bat add_user username password
示例:
rabbitmqctl.bat add_user tangsansan 123456

rabbitmqctl.bat set_user_tags username administrator

示例:
rabbitmqctl.bat set_user_tags tangsansan administrator

基本用法

引入:RabbitMQ.Client

消费者

	    //创建连接工厂
	        ConnectionFactory factory = new ConnectionFactory
	        {
		        UserName = "tangsansan",//用户名
                        Password = "123456",//密码
                        HostName = "localhost"//rabbitmq ip
	        };

	        //创建连接
	        var connection = factory.CreateConnection();
	        //创建通道
	        var channel = connection.CreateModel();

			//事件基本消费者
			EventingBasicConsumer consumer = new EventingBasicConsumer(channel);

			//接收到消息事件
	        consumer.Received += (ch, ea) =>
	        {
		        var message = Encoding.UTF8.GetString(ea.Body);
		        Console.WriteLine($"收到消息: {message}");
				//确认该消息已被消费
		        channel.BasicAck(ea.DeliveryTag, false);
			};
			//启动消费者 设置为手动应答消息
			channel.BasicConsume("hello", false, consumer);
	        Console.WriteLine("消费者已启动");
	        Console.ReadKey();
	        channel.Dispose();
	        connection.Close();

生产者

 //创建连接工厂
            var factory = new ConnectionFactory()
            {
                UserName = "tangsansan",//用户名
                Password = "123456",//密码
                HostName = "localhost"//rabbitmq ip
            };

            //创建连接
            var connection = factory.CreateConnection();
            //创建通道
            var channel = connection.CreateModel();
            //定义一个队列
            channel.QueueDeclare("hello", false, false, false, null);
            Console.WriteLine("\nRabbitMQ连接成功,请输入消息,输入exit退出!");

            string input;
            do
            {
                input = Console.ReadLine();

                var sendBytes = Encoding.UTF8.GetBytes(input);
                //发布消息
                channel.BasicPublish("", "hello", null, sendBytes);

            } while (input.Trim().ToLower() != "exit");

            channel.Close();
            connection.Close();

启动了一个生产者,两个消费者,可以看见两个消费者都能收到消息,消息投递到哪个消费者是由RabbitMQ决定的。

RabbitMQ消费失败的处理

RabbitMQ采用消息应答机制,即消费者收到一个消息之后,需要发送一个应答,然后RabbitMQ才会将这个消息从队列中删除,如果消费者在消费过程中出现异常,断开连接切没有发送应答,那么RabbitMQ会将这个消息重新投递

//接收到消息事件
consumer.Received += (ch, ea) =>
{
    var message = Encoding.UTF8.GetString(ea.Body);

    Console.WriteLine($"收到消息: {message}");

    Console.WriteLine($"收到该消息[{ea.DeliveryTag}] 延迟10s发送回执");
    Thread.Sleep(10000);
    //确认该消息已被消费
    channel.BasicAck(ea.DeliveryTag, false);
    Console.WriteLine($"已发送回执[{ea.DeliveryTag}]");
};

使用RabbitMQ的Exchange

前面我们可以看到生产者将消息投递到Queue中,实际上这在RabbitMQ中这种事情永远都不会发生。实际的情况是,生产者将消息发送到Exchange(交换器),由Exchange将消息路由到一个或多个Queue中(或者丢弃)
生产者将消息发送到Exchange(交换器),由Exchange将消息路由到一个或多个Queue中(或者丢弃)

Direct Exchange

【直接交换(按RouteKey)】:
直接按照绑定的RouteKey生产消费。

            string exchangeName = "TestChange";
            string queueName = "hello";
            string routeKey = "helloRouteKey";

            //创建连接工厂
            var factory = new ConnectionFactory()
            {
                UserName = "tangsansan",//用户名
                Password = "123456",//密码
                HostName = "localhost"//rabbitmq ip
            };

            //创建连接
            var connection = factory.CreateConnection();
            //创建通道
            var channel = connection.CreateModel();

            //定义一个Direct类型交换机
            channel.ExchangeDeclare(exchangeName, ExchangeType.Direct, false, false, null);

            //定义一个队列
            channel.QueueDeclare(queueName, false, false, false, null);

            //将队列绑定到交换机
            channel.QueueBind(queueName, exchangeName, routeKey, null);

           Console.WriteLine($"\nRabbitMQ连接成功,Exchange:{exchangeName},Queue:{queueName},Route:{routeKey},\n\n请输入消息,输入exit退出!");

            string input;
            do
            {
                input = Console.ReadLine();

                var sendBytes = Encoding.UTF8.GetBytes(input);
                //发布消息
                channel.BasicPublish(exchangeName, routeKey, null, sendBytes);

            } while (input.Trim().ToLower() != "exit");

            channel.Close();
            connection.Close();

Fanout Exchange

【分发】:
所有绑定fanout exchange队列发送的消息,会被所有绑定fanout exchange队列的消费者消费掉。不按RouteKey处理。

所有发送到Fanout Exchange的消息都会被转发到与该Exchange 绑定(Binding)的所有Queue上。

Fanout Exchange 不需要处理RouteKey 。只需要简单的将队列绑定到exchange 上。这样发送到exchange的消息都会被转发到与该交换机绑定的所有队列上。类似子网广播,每台子网内的主机都获得了一份复制的消息。

所以,Fanout Exchange 转发消息是最快的。

static void Main(string[] args)
        {
            string exchangeName = "TestFanoutChange";
            string queueName1 = "hello1";
            string queueName2 = "hello";
            string routeKey = "";

            //创建连接工厂
            ConnectionFactory factory = new ConnectionFactory
            {
                UserName = "tangsansan",//用户名
                Password = "123456",//密码
                HostName = "localhost"//rabbitmq ip
            };

            //创建连接
            var connection = factory.CreateConnection();
            //创建通道
            var channel = connection.CreateModel();

            //定义一个Direct类型交换机
            channel.ExchangeDeclare(exchangeName, ExchangeType.Fanout, false, false, null);

            //定义队列1
            channel.QueueDeclare(queueName1, false, false, false, null);
            //定义队列2
            channel.QueueDeclare(queueName2, false, false, false, null);

            //将队列绑定到交换机
            channel.QueueBind(queueName1, exchangeName, routeKey, null);
            channel.QueueBind(queueName2, exchangeName, routeKey, null);

            //生成两个队列的消费者
            ConsumerGenerator(queueName1);
            ConsumerGenerator(queueName2);


            Console.WriteLine($"\nRabbitMQ连接成功,\n\n请输入消息,输入exit退出!");

            string input;
            do
            {
                input = Console.ReadLine();

                var sendBytes = Encoding.UTF8.GetBytes(input);
                //发布消息
                channel.BasicPublish(exchangeName, routeKey, null, sendBytes);

            } while (input.Trim().ToLower() != "exit");
            channel.Close();
            connection.Close();
        }

        /// <summary>
        /// 根据队列名称生成消费者
        /// </summary>
        /// <param name="queueName"></param>
        static void ConsumerGenerator(string queueName)
        {
            //创建连接工厂
            ConnectionFactory factory = new ConnectionFactory
            {
                UserName = "tangsansan",//用户名
                Password = "123456",//密码
                HostName = "localhost"//rabbitmq ip
            };

            //创建连接
            var connection = factory.CreateConnection();
            //创建通道
            var channel = connection.CreateModel();

            //事件基本消费者
            EventingBasicConsumer consumer = new EventingBasicConsumer(channel);

            //接收到消息事件
            consumer.Received += (ch, ea) =>
            {
                var message = Encoding.UTF8.GetString(ea.Body);

                Console.WriteLine($"Queue:{queueName}收到消息: {message}");
                //确认该消息已被消费
                channel.BasicAck(ea.DeliveryTag, false);
            };
            //启动消费者 设置为手动应答消息
            channel.BasicConsume(queueName, false, consumer);
            Console.WriteLine($"Queue:{queueName},消费者已启动");
        }

Topic Exchange


所有发送到Topic Exchange的消息被转发到能和Topic匹配的Queue上,

Exchange 将路由进行模糊匹配。可以使用通配符进行模糊匹配,符号“#”匹配一个或多个词,符号“”匹配不多不少一个词。因此“XiaoChen.#”能够匹配到“XiaoChen.pets.cat”,但是“XiaoChen.” 只会匹配到“XiaoChen.money”。

所以,Topic Exchange 使用非常灵活。

      static void Main(string[] args)
        {
            string exchangeName = "TestTopicChange";
            string queueName = "hello";
            string routeKey = "TestRouteKey.*";

            //创建连接工厂
            ConnectionFactory factory = new ConnectionFactory
            {
                UserName = "tangsansan",//用户名
                Password = "123456",//密码
                HostName = "localhost"//rabbitmq ip
            };

            //创建连接
            var connection = factory.CreateConnection();
            //创建通道
            var channel = connection.CreateModel();

            //定义一个Direct类型交换机
            channel.ExchangeDeclare(exchangeName, ExchangeType.Topic, false, false, null);

            //定义队列1
            channel.QueueDeclare(queueName, false, false, false, null);

            //将队列绑定到交换机
            channel.QueueBind(queueName, exchangeName, routeKey, null);



            Console.WriteLine($"\nRabbitMQ连接成功,\n\n请输入消息,输入exit退出!");

            string input;
            do
            {
                input = Console.ReadLine();

                var sendBytes = Encoding.UTF8.GetBytes(input);
                //发布消息
                channel.BasicPublish(exchangeName, "TestRouteKey.one", null, sendBytes);

            } while (input.Trim().ToLower() != "exit");
            channel.Close();
            connection.Close();
        }

问题:

None of the specified endpoints were reachable

这个异常在创建连接时抛出(CreateConnection()),原因一般是ConnectionFactory参数设置不对,比如HostName、UserName、Password
未设置VirtualHost的权限
设置方法:RabbitmqWeb管理网站-->Admin

posted @ 2018-12-06 20:20  【唐】三三  阅读(601)  评论(1编辑  收藏  举报