/// <summary> /// 添加信息到队列 /// </summary> public static void PushMsgToMq(RbtMessage msg, string EXCHANGE_NAME = null, string EXCHANGE_TYPE = ExchangeType.Topic) { bool IsFanout = false; string routingKey = msg.Routingkey; if (EXCHANGE_TYPE == ExchangeType.Fanout) { IsFanout = true; //广播模式 // routingKey = ""; EXCHANGE_NAME = EXCHANGE_NAME ?? "amq.topic"; } else { EXCHANGE_NAME = EXCHANGE_NAME ?? "amq.topic"; } try { if (connection == null) { return; } string jsonMsg = JsonConvert.SerializeObject(msg); using (IModel channel = connection.CreateModel()) { if (IsFanout) { channel.ExchangeDeclare(EXCHANGE_NAME, ExchangeType.Fanout); } else { channel.QueueDeclare(queue: routingKey, durable: true, exclusive: false, autoDelete: false, arguments: null); } IBasicProperties properties = channel.CreateBasicProperties(); properties.Persistent = true; byte[] body = Encoding.UTF8.GetBytes(jsonMsg); channel.BasicPublish(exchange: EXCHANGE_NAME, routingKey: routingKey, basicProperties: properties, body: body); } } catch (Exception ex) { // MstCore.Pub.MstPub.Logs("RabbitMQ出错:" + ex.ToString()); } }
// Func<RbtMessage, bool> func, public void BindReceiveMqMsg(Func <RbtMessage, bool> func, ICallbackFunction function, string routingKey, string EXCHANGE_NAME = null, string exchange_type = null) { try { //创建与指定端点的连接。 connection = RbtMQConnection._connectionFactory.CreateConnection(); //创建并返回新的频道,会话和模型。 channel = connection.CreateModel(); bool IsFanout = false;//广播方式 if (exchange_type == ExchangeType.Fanout) { //广播方式 IsFanout = true; EXCHANGE_NAME = EXCHANGE_NAME ?? "amq.topic"; } else { EXCHANGE_NAME = EXCHANGE_NAME ?? "amq.topic"; exchange_type = ExchangeType.Topic; } channel.ExchangeDeclare(exchange: EXCHANGE_NAME, type: exchange_type, durable: true); if (!IsFanout) { this.channel.QueueDeclare(queue: routingKey, //队列名称 durable: true, //是否持久化, 队列的声明默认是存放到内存中的,如果rabbitmq重启会丢失,如果想重启之后还存在就要使队列持久化,保存到Erlang自带的Mnesia数据库中,当rabbitmq重启之后会读取该数据库 exclusive: false, //是否排外的,有两个作用,一:当连接关闭时connection.close()该队列是否会自动删除;二:该队列是否是私有的private,如果不是排外的,可以使用两个消费者都访问同一个队列,没有任何问题,如果是排外的,会对当前队列加锁,其他通道channel是不能访问的,如果强制访问会报异常:com.rabbitmq.client.ShutdownSignalException: channel error; protocol method: #method<channel.close>(reply-code=405, reply-text=RESOURCE_LOCKED - cannot obtain exclusive access to locked queue 'queue_name' in vhost '/', class-id=50, method-id=20)一般等于true的话用于一个队列只能有一个消费者来消费的场景 autoDelete: false, //是否自动删除,当最后一个消费者断开连接之后队列是否自动被删除,可以通过RabbitMQ Management,查看某个队列的消费者数量,当consumers = 0时队列就会自动删除 arguments: null); //队列中的消息什么时候会自动被删除? } else { routingKey = channel.QueueDeclare().QueueName; } channel.QueueBind(routingKey, EXCHANGE_NAME, "amq.topic"); //Map<String, Object> args = new HashMap<String, Object>(); //args.put("x-max-length", 10); // channel.QueueDeclare("routingKey", false, false, false, args); //(Spec方法)配置Basic内容类的QoS参数。 //第一个参数是可接收消息的大小的 0不受限制 //第二个参数是处理消息最大的数量 1 那如果接收一个消息,但是没有应答,则客户端不会收到下一个消息,消息只会在队列中阻塞 //第三个参数则设置了是不是针对整个Connection的,因为一个Connection可以有多个Channel,如果是false则说明只是针对于这个Channel的。 // basic.qos是针对channel进行设置的,也就是说只有在channel建立之后才能发送basic.qos信令。 //在rabbitmq的实现中,每个channel都对应会有一个rabbit_limiter进程,当收到basic.qos信令后,在rabbit_limiter进程中记录信令中prefetch_count的值,同时记录的还有该channel未ack的消息个数。 channel.BasicQos(prefetchSize: 0, prefetchCount: 1, global: false);//该方法可以看出休息小半秒和一秒的区别 //构造函数,它将Model属性设置为给定值。 // EventingBasicConsumer是基于长连接,发布订阅模式的消费方式,节省资源且实时性好,这是开发中最常用的消费模式。在一些需要消费者主动获取消息的场合,我们可以使用Get方式,Get方式是基于短连接的,请求响应模式的消费方式。 EventingBasicConsumer consumer = new EventingBasicConsumer(this.channel); // 2.种 //BasicGetResult result = channel.BasicGet(queue:"routingKey",autoAck:true); //接收到消息时触发的事件 consumer.Received += (model, bdea) => { byte[] body = bdea.Body.ToArray(); string message = Encoding.UTF8.GetString(body); if (message == null || message.Length == 0) { // 将BasicConsume方法的autoAck设置为false,然后处理一条消息后手动确认一下,这样的话已处理的消息在接收到确认回执时被删除,未处理的消息以Unacked状态存放在queue中。如果消费者挂了,Unacked状态的消息会自动重新变成Ready状态,如此一来就不用担心消息丢失,true会一次性发完 this.channel.BasicAck(deliveryTag: bdea.DeliveryTag, multiple: false); return; } // 开启持久化功能,需同时满足:消息投递模式选择持久化、交换器开启持久化、队列开启持久化 RbtMessage mqMsg = JsonConvert.DeserializeObject <RbtMessage>(message); function.ProcessMsgAsync(mqMsg); //通过回调来确认是否处理成功,如果成功,返回true,表示确认OK bool result = true; if (func != null) { result = func(mqMsg); } if (result) { //(Spec方法)确认一个或多个已传送的消息。 channel.BasicAck(deliveryTag: bdea.DeliveryTag, multiple: false); } }; channel.BasicConsume(queue: routingKey, autoAck: false, consumer: consumer); } catch (Exception ex) { // MstCore.Pub.MstPub.Logs("RabbitMQ出错:" + ex.ToString()); } }