一.Hello World
生产者
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using RabbitMQ.Client;
using RabbitMQ.Client.Framing.Impl;
namespace Hello
{
class Program
{
static void Main(string[] args)
{
var factory = new ConnectionFactory();//创建连接
factory.HostName = "localhost"; //设置目标,如果RabbitMQ不在本机,只需要设置目标机器的IP地址或者机器名称即可
factory.UserName = "guest"; //设置用户名
factory.Password = "guest"; //设置对应的密码
using (var connection = factory.CreateConnection())//创建连接
{
using (var channel = connection.CreateModel())//创建通道
{
//队列声明 发送端队列声明要与此处的一致
channel.QueueDeclare("hello", false, false, true, null);//要发送的信息 是否持久化 是否私有的 连接关闭时是否删除队列 参数
string message = "共有100个信息";
var body = Encoding.UTF8.GetBytes(message);//组织 要发送的信息
channel.BasicPublish("", "hello", null, body);//把信息发送到队列channel里
Console.WriteLine(" 信息 {0}", message);
int msgNum = 100;
while (true)
{
Thread.Sleep(300);
message = "发送:这是第" + msgNum + "个Hello World";
body = Encoding.UTF8.GetBytes(message);
channel.BasicPublish("", "hello", null, body);
Console.WriteLine(" 信息 {0}", message);
msgNum--;
if (msgNum == 0)
{
message = "信息发送完毕";
body = Encoding.UTF8.GetBytes(message);
channel.BasicPublish("", "hello", null, body);//第一个参数是交换区的名字 第二个是消息队列的名字 第三个是参数 第四个是发送的信息
Console.WriteLine(" 信息 {0}", message);
Console.ReadLine();
break;
}
}
}
}
}
}
}
消费者
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;
using RabbitMQ.Client;
using RabbitMQ.Client.Events;
namespace HelloReceive
{
class Program
{
static void Main(string[] args)
{
#region 声明链接
var factory = new ConnectionFactory(); //创建连接
factory.HostName = "localhost"; //设置目标,如果RabbitMQ不在本机,只需要设置目标机器的IP地址或者机器名称即可
factory.UserName = "guest"; //设置用户名
factory.Password = "guest"; //设置对应的密码
#endregion
using (var connection=factory.CreateConnection())//建立连接
{
using (var channel=connection.CreateModel())//建立通道
{
#region 消息队列与客户端绑定
//队列声明 此处的队列声明要与发送端一致
channel.QueueDeclare("hello", false, false, true, null); //要发送的信息 是否持久化 是否私有的 连接关闭时是否删除队列 参数
var consumer = new QueueingBasicConsumer(channel); //在通道channel里添加消费者
channel.BasicConsume("hello", true, consumer);//消费者订阅队列 // 消息队列的名字 是否关闭消息响应 消费者的名字
//channel.BasicCancel(consumer.ConsumerTag);//停止订阅
#endregion
Console.WriteLine(" waiting for message.");
#region 接收信息
while (true)
{
var ea = (BasicDeliverEventArgs) consumer.Queue.Dequeue(); //队列里的信息出列
var body = ea.Body;
var message = Encoding.UTF8.GetString(body);
Console.WriteLine("接收: {0}", message);
}
#endregion
}
}
}
}
}
二.工作队列(轮询分发)
生产者
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using RabbitMQ.Client;
namespace RMQ_WorkQueuesSend
{
class Program
{
static void Main(string[] args)
{
var factory = new ConnectionFactory();
factory.HostName = "localhost";
factory.UserName = "guest";
factory.Password = "guest";
using (var connection=factory.CreateConnection())
{
using (var channel=connection.CreateModel())
{
channel.QueueDeclare("WorkQueues", false, false, false, null);
while (true)
{
string message = GetMessage(args);
var body = Encoding.UTF8.GetBytes(message);
channel.BasicPublish("", "WorkQueues", null, body);
Console.WriteLine("发送:" + message);
}
}
}
}
private static string GetMessage(string[] args)
{
return Console.ReadLine();
}
}
}
消费者1
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using RabbitMQ.Client;
using RabbitMQ.Client.Events;
namespace RMQ_WorkQueuesReceive
{
class Program
{
static void Main(string[] args)
{
var factory = new ConnectionFactory();
factory.HostName = "localhost";
factory.UserName = "guest";
factory.Password = "guest";
using (var connection = factory.CreateConnection())
{
using (var channel = connection.CreateModel())
{
channel.QueueDeclare("WorkQueues", false, false, false, null);
var consumer=new QueueingBasicConsumer(channel);
channel.BasicConsume("WorkQueues", true, consumer);
while (true)
{
var ea = (BasicDeliverEventArgs)consumer.Queue.Dequeue();
var body = ea.Body;
var message = Encoding.UTF8.GetString(body);
Console.WriteLine("接收端1:" + message + Environment.NewLine);
}
}
}
}
}
}
消费者2
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using RabbitMQ.Client;
using RabbitMQ.Client.Events;
namespace RMQ_WorkerReceive
{
class Program
{
static void Main(string[] args)
{
var factory = new ConnectionFactory();
factory.HostName = "localhost";
factory.UserName = "guest";
factory.Password = "guest";
using (var connection = factory.CreateConnection())
{
using (var channel=connection.CreateModel())
{
channel.QueueDeclare("WorkQueues", false, false, false, null);
var consumer = new QueueingBasicConsumer(channel);
channel.BasicConsume("WorkQueues", true, consumer);
while (true)
{
var ea = (BasicDeliverEventArgs)consumer.Queue.Dequeue();
var body = ea.Body;
var message = Encoding.UTF8.GetString(body);
Console.WriteLine("接收端2:" + message + Environment.NewLine);
}
}
}
}
}
}
二.工作队列(公平分发)
要和消息响应一起使用
你可能会注意到,消息的分发可能并没有如我们想要的那样公平分配。比如,对于两个工作者。
当奇数个消息的任务比较重,但是偶数个消息任务比较轻时,奇数个工作者始终处理忙碌状态,
而偶数个工作者始终处理空闲状态。但是RabbitMQ并不知道这些,他仍然会平均依次的分发消息。
为了改变这一状态,我们可以使用basicQos
方法,设置perfetchCount=1
。
这样就告诉RabbitMQ不要在同一时间给一个工作者发送多于1个的消息,或者换句话说。
在一个工作者还在处理消息,并且没有响应消息之前,不要给他分发新的消息。相反,将这条新的消息发送给下一个不那么忙碌的工作者。
channel.BasicQos(0, 1, false);
公平分发解决的问题就是 消息优先发送给空闲的worker
RMQ_BasicQos_ReceiveOne
和RMQ_BasicQos_ReceiveSecond
接收时 都是通过循环的方式来做
RMQ_BasicQos_ReceiveThree
接收的时候 不通过while循环的方式
生产者
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Security.Policy;
using System.Text;
using RabbitMQ;
using RabbitMQ.Client;
namespace RMQ_BasicQos_Send
{
class Program
{
static void Main(string[] args)
{
string[] location=new string[]
{
"localhost",
"123.206.216.30"
};
var factory = new ConnectionFactory();
factory.HostName = location[0];
factory.UserName = "guest";
factory.Password = "guest";
using (var connetion = factory.CreateConnection())
{
using (var channel = connetion.CreateModel())
{
//第二个参数设置队列持久化 避免服务器重启 信息丢失
channel.QueueDeclare("Lasting_queue", true, false, true, null);//要发送的信息 是否持久化 是否私有的 连接关闭时是否删除队列 参数
channel.QueueDeclare("Lasting_queue1", true, false, true, null);//要发送的信息 是否持久化 是否私有的 连接关闭时是否删除队列 参数
channel.QueueDeclare("Lasting_queue2", true, false, true, null);//要发送的信息 是否持久化 是否私有的 连接关闭时是否删除队列 参数
var properties = channel.CreateBasicProperties();
properties.DeliveryMode = 2;
properties.SetPersistent(true); //设置消息持久化
while (true)
{
string[] message = GetMessage().Split(' ');
byte[] body;
if (!connetion.IsOpen)
{
Console.WriteLine("与服务器连接断开");
continue;
}
if (message.Length<=0)
continue;
body = Encoding.UTF8.GetBytes(message[0]);
channel.BasicPublish("", "Lasting_queue", properties, body);
Console.WriteLine("发送:" + message[0]);
if (message.Length <= 1)
continue;
body = Encoding.UTF8.GetBytes(message[1]);
channel.BasicPublish("", "Lasting_queue1", properties, body);
Console.WriteLine("发送1:" + message[1]);
if (message.Length <= 2)
continue;
body = Encoding.UTF8.GetBytes(message[2]);
channel.BasicPublish("", "Lasting_queue2", properties, body);
Console.WriteLine("发送2:" + message[2]);
}
}
}
}
private static string GetMessage()
{
return Console.ReadLine();
}
}
}
消费者1
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using RabbitMQ;
using RabbitMQ.Client;
using RabbitMQ.Client.Events;
using RabbitMQ.Client.Framing;
namespace RMQ_BasicQos_ReceiveOne
{
class Program
{
static void Main(string[] args)
{
string[] location = new string[]
{
"localhost",
"123.206.216.30"
};
var factory=new ConnectionFactory();
factory.HostName = location[1];
factory.UserName = "guest";
factory.Password = "guest";
using (var connection=factory.CreateConnection())
{
using (var channel=connection.CreateModel())
{
channel.QueueDeclare("Lasting_queue", true, false, true, null);
channel.BasicQos(0, 1, false);//设置该客户在同一时间 RabbitMQ只发给该客户一个消息,在该客户没有响应消息之前不要给他分发消息将这条新的消息发送给下一个不那么忙碌的工作者。
var consumer = new QueueingBasicConsumer(channel);
channel.BasicConsume("Lasting_queue", false, consumer);
while (true)
{
var ea = (BasicDeliverEventArgs)consumer.Queue.Dequeue();
var body = ea.Body;
var message = Encoding.UTF8.GetString(body);
Console.WriteLine("接收:" + message);
channel.BasicAck(ea.DeliveryTag, false);//消息消息响应
}
}
}
}
}
}
消费者2
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using RabbitMQ.Client;
using RabbitMQ.Client.Events;
namespace RMQ_BasicQos_ReceiveSecond
{
class Program
{
static void Main(string[] args)
{
var factory = new ConnectionFactory();
factory.HostName = "localhost";
factory.UserName = "guest";
factory.Password = "guest";
using (var connection = factory.CreateConnection())
{
using (var channel = connection.CreateModel())
{
channel.QueueDeclare("Lasting_queue1", true, false, true, null);
channel.BasicQos(0, 1, false);//设置该客户在同一时间 RabbitMQ只发给该客户一个消息,在该客户没有响应消息之前不要给他分发消息将这条新的消息发送给下一个不那么忙碌的工作者。
var consumer = new QueueingBasicConsumer(channel);
channel.BasicConsume("Lasting_queue1", false, consumer);
while (true)
{
var ea = (BasicDeliverEventArgs)consumer.Queue.Dequeue();
var body = ea.Body;
var message = Encoding.UTF8.GetString(body);
//int dots = message.Split(',').Length - 1;
//Thread.Sleep(1000 * dots);
Console.WriteLine("接收:" + message);
channel.BasicAck(ea.DeliveryTag, false);//消息消息响应
}
}
}
}
}
}
消费者3
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using RabbitMQ.Client;
using RabbitMQ.Client.Events;
namespace RMQ_BasicQos_ReceiveThree
{
class Program
{
static void Main(string[] args)
{
string[] location = new string[]
{
"localhost",
"123.206.216.30"
};
var factory = new ConnectionFactory();
factory.HostName = location[0];
factory.UserName = "guest";
factory.Password = "guest";
var connection = factory.CreateConnection();
var channel = connection.CreateModel();
channel.QueueDeclare("Lasting_queue1", true, false, true, null);
channel.QueueDeclare("Lasting_queue2", true, false, true, null);//要发送的信息 是否持久化 是否私有的 连接关闭时是否删除队列 参数
channel.BasicQos(0, 1, false);//设置该客户在同一时间 RabbitMQ只发给该客户一个消息,在该客户没有响应消息之前不要给他分发消息将这条新的消息发送给下一个不那么忙碌的工作者。
var consumer = new EventingBasicConsumer(channel);
channel.BasicConsume("Lasting_queue1", false, consumer);
channel.BasicConsume("Lasting_queue2", false, consumer);
consumer.Received += consumer_Received;
}
static void consumer_Received(object sender, BasicDeliverEventArgs args)
{
IBasicConsumer basicConsumer = sender as IBasicConsumer;
var body = args.Body;
var message = Encoding.UTF8.GetString(body);
Console.WriteLine("接收:" + args.DeliveryTag.ToString()+"\t" + message);
basicConsumer.Model.BasicAck(args.DeliveryTag, false);//消息消息响应
}
}
}
三.发布/订阅(Exchanges)
RabbitMQ的Exchange
类型有4种,direct,fanout,topic,headers
。
报消息发到Exchange
上 当有一个消费者接收到了消息,其他的消费者仍然可以去该Exchange
上去接收
fanout
广播类型direct
根据routingKey
全字匹配topic
根据routingKey
模糊匹配
这个类型的路由规则如果你掌握啦,那是相当的好用,与灵活。他是根据RoutingKey
的设置,来做匹配的,其中这里还有两个通配符为:
*
,代表任意的一个词。例如topic.zlh.*
,他能够匹配到,topic.zlh.one ,topic.zlh.two ,topic.zlh.abc, ....
#
,代表任意多个词。例如topic.#
,他能够匹配到,topic.zlh.one ,topic.zlh.two ,topic.zlh.abc, topic.zlh.abc.edg,....
headers
忽略routingKey
的一种路由方式 但是是使用Headers
来匹配的Headers
是一个键值对,可以定义成Dictionary
匹配有两种方式all
和any
。这两种方式是在接收端必须要用键值”x-mactch
“来定义。all
代表定义的多个键值对都要满足,而any
则代码只要满足一个就可以了。
在Exchange
还没有绑定队列的时候向Exchange
里发送信息Exchange
会把信息丢掉
三.Exchanges的direct类型
生产者
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using RabbitMQ.Client;
namespace Excehange_Direct_Send
{
class Program
{
static void Main(string[] args)
{
var queueName = "ExchangDirect_queue1";//消息队列的名字
var exchangeName = "ExchangeDirect"; //交换器的名字
var exchangeType = "direct";//topic、fanout、direct fanout为广播类型
var routingKey = "abc.a"; //关键字
var factory = new ConnectionFactory()
{
HostName = "localhost",
UserName = "guest",
Password = "guest"
};
using (var connetion = factory.CreateConnection())
{
using (var channel = connetion.CreateModel())
{
//Exchange的名字 类型 是否持久化 是否自动删除 参数
channel.ExchangeDeclare(exchangeName, exchangeType, false, true, null);
while (true)
{
string message = GetMessage();
var body = Encoding.UTF8.GetBytes(message);
channel.BasicPublish(exchangeName, routingKey, null, body);
Console.WriteLine("发送到Exchange:" + message);
}
}
}
}
private static string GetMessage()
{
return Console.ReadLine();
}
}
}
消费者
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using RabbitMQ.Client;
using RabbitMQ.Client.Events;
namespace RMQ_ReceiveOne
{
class Program
{
static void Main(string[] args)
{
var queueName = "ExchangDirect_queue1";//消息队列的名字
var exchangeName = "ExchangeDirect"; //交换器的名字
var exchangeType = "direct";//topic、fanout、direct fanout为广播类型
var routingKey = "abc.a"; //关键字
var factory = new ConnectionFactory()
{
HostName = "localhost",
UserName = "guest",
Password = "guest"
};
var connection = factory.CreateConnection();
var channel = connection.CreateModel();
channel.QueueDeclare(queueName, false, false, true, null);
channel.QueueBind(queueName,exchangeName,routingKey);
var consumer=new EventingBasicConsumer(channel);
channel.BasicConsume(queueName, false, consumer);
consumer.Received += consumer_Received;
}
private static void consumer_Received(object sender, BasicDeliverEventArgs e)
{
IBasicConsumer basicConsumer = sender as IBasicConsumer;
var body = e.Body;
var message = Encoding.UTF8.GetString(body);
Console.WriteLine("收到ExchangeDirect:" + message);
if (basicConsumer != null) basicConsumer.Model.BasicAck(e.DeliveryTag, false);
}
}
}
三.Exchanges的topic类型
生产者
using System;
using System.Runtime.InteropServices;
using System.Text;
using RabbitMQ.Client;
namespace RMQ_Send
{
class Program
{
static void Main(string[] args)
{
var queueName = "Exchang_queue1";//消息队列的名字
var exchangeName = "MyExchange"; //交换器的名字
var exchangeType = "topic";//topic、fanout、direct fanout为广播类型
var routingKey = "abc.a"; //关键字
var factory = new ConnectionFactory()
{
HostName = "localhost",
UserName = "guest",
Password = "guest"
};
using (var connetion = factory.CreateConnection())
{
using (var channel = connetion.CreateModel())
{
//Exchange的名字 类型 是否持久化 是否自动删除 参数
channel.ExchangeDeclare(exchangeName, exchangeType, false , true, null);
//var properties = channel.CreateBasicProperties(); //消息持久化
//properties.DeliveryMode = 2;
while (true)
{
string message = GetMessage();
var body = Encoding.UTF8.GetBytes(message);
channel.BasicPublish(exchangeName, routingKey, null, body);
Console.WriteLine("发送到Exchange:" + message);
}
}
}
}
private static string GetMessage()
{
return Console.ReadLine();
}
}
}
消费者
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using RabbitMQ.Client;
using RabbitMQ.Client.Events;
namespace RMQ_ReceiveThree
{
class Program
{
static void Main(string[] args)
{
var queueName = "Exchang_queue1";//消息队列的名字
var exchangeName = "MyExchange"; //交换器的名字
var exchangeType = "topic";//topic、fanout
var routingKey = "abc.*"; //关键字
var factory = new ConnectionFactory()
{
HostName = "localhost",
UserName = "guest",
Password = "guest"
};
var connection = factory.CreateConnection();
var channel = connection.CreateModel();
channel.ExchangeDeclare(exchangeName, exchangeType, false, true, null);
//需要先建立消息队列
channel.QueueDeclare(queueName, false, false, true, null);
channel.QueueBind(queueName, exchangeName, routingKey);
/*channel.BasicQos(0,1, false);//设置该客户在同一时间 RabbitMQ只发给该客户一个消息,
*在该客户没有响应消息之前不要给他分发消息将这条新的消息发送给下一个不那么忙碌的工作者。 参数说明
*prefetchSize 预读的个数
*prefetchCount:会告诉RabbitMQ不要同时给一个消费者推送多于N个消息,即一旦有N个消息还没有ack,则该consumer将block掉,直到有消息ack
*global:true\false 是否将上面设置应用于channel,简单点说,就是上面限制是channel级别的还是consumer级别
*/
var consumer = new EventingBasicConsumer(channel);
channel.BasicConsume(queueName, false, consumer);//接收到信息时不发送信息响应
consumer.Received += consumer_Received;
}
static void consumer_Received(object sender, BasicDeliverEventArgs args)
{
IBasicConsumer basicConsumer = sender as IBasicConsumer;
var body = args.Body;
var message = Encoding.UTF8.GetString(body);
Console.WriteLine("收到:" + message);
//basicConsumer.Model.BasicAck(args.DeliveryTag, false);//把信息处理完后再发送消息响应
}
}
}
三.Exchanges的headers类型
生产者
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net.Cache;
using System.Text;
using System.Xml.Serialization;
using RabbitMQ.Client;
namespace RMQExchange_Header_Send
{
class Program
{
static void Main(string[] args)
{
var queueName = "Exchang_Headers_queue";//消息队列的名字
var exchangeName = "Exchange_Headers"; //交换器的名字
var exchangeType = "headers";//topic、fanout、direct、headers fanout为广播类型
//var routingKey = "abc.a"; //关键字
var factory = new ConnectionFactory()
{
HostName = "localhost",
UserName = "guest",
Password = "guest"
};
using (var connection = factory.CreateConnection())
{
using (var channel = connection.CreateModel())
{
channel.ExchangeDeclare(exchangeName,exchangeType,false,true,null);
var properties = channel.CreateBasicProperties();
properties.Headers = new Dictionary<string, object>();
while (true)
{
string[] message = GetMessage().Split(' ');
properties.Headers.Clear();
properties.Headers.Add("key1", "123");
channel.BasicPublish(exchangeName, "", properties, Encoding.UTF8.GetBytes(message[0]));
Console.WriteLine("发送到" + exchangeName + ":" + message[0]);
properties.Headers.Clear();
properties.Headers.Add("key2","123abc");
channel.BasicPublish(exchangeName, "", properties, Encoding.UTF8.GetBytes(message[1]));
Console.WriteLine("发送到" + exchangeName + ":" + message[1]);
}
}
}
}
private static string GetMessage()
{
return Console.ReadLine();
}
}
}
消费者1
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using RabbitMQ.Client;
using RabbitMQ.Client.Events;
namespace RMQExchange_Header_Receive
{
class Program
{
static void Main(string[] args)
{
var queueName = "Exchang_Headers_queue";
var exchangeName = "Exchange_Headers";
var exchangeType = "headers";//topic、fanout、direct fanout为广播类型
var factory = new ConnectionFactory()
{
HostName = "localhost",
UserName = "guest",
Password = "guest"
};
var connetion = factory.CreateConnection();
var channel = connetion.CreateModel();
channel.ExchangeDeclare(exchangeName, exchangeType, false, true, null);
var htDictionary = new Dictionary<string,object>();
htDictionary.Add("x-match", "any");
htDictionary.Add("key1", "123");
htDictionary.Add("key2", "123abc");
channel.QueueDeclare(queueName, false, false, true, null);
channel.QueueBind(queueName, exchangeName, "", htDictionary);
var consumer =new EventingBasicConsumer(channel);
channel.BasicConsume(queueName, false, consumer);//订阅
consumer.Received += consumer_Received;
}
static void consumer_Received(object sender, BasicDeliverEventArgs args)
{
IBasicConsumer basicConsumer = sender as IBasicConsumer;
var body = args.Body;
var message = Encoding.UTF8.GetString(body);
Console.WriteLine("收到:"+message);
//消息响应
if (basicConsumer != null) basicConsumer.Model.BasicAck(args.DeliveryTag, false);
}
}
}
消费者2
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using RabbitMQ.Client;
using RabbitMQ.Client.Events;
namespace RMQExchange_Header_Receive
{
class Program
{
static void Main(string[] args)
{
var queueName = "Exchang_Headers_queueOther";
var exchangeName = "Exchange_Headers";
var exchangeType = "headers";//topic、fanout、direct fanout为广播类型
var factory = new ConnectionFactory()
{
HostName = "localhost",
UserName = "guest",
Password = "guest"
};
var connetion = factory.CreateConnection();
var channel = connetion.CreateModel();
channel.ExchangeDeclare(exchangeName, exchangeType, false, true, null);
var htDictionary = new Dictionary<string, object>();
htDictionary.Add("x-match", "any");
htDictionary.Add("key1", "123");
htDictionary.Add("key2", "123abc");
channel.QueueDeclare(queueName, false, false, true, null);
channel.QueueBind(queueName, exchangeName, "", htDictionary);
var consumer = new EventingBasicConsumer(channel);
channel.BasicConsume(queueName, false, consumer);//订阅
consumer.Received += consumer_Received;
}
static void consumer_Received(object sender, BasicDeliverEventArgs args)
{
IBasicConsumer basicConsumer = sender as IBasicConsumer;
var body = args.Body;
var message = Encoding.UTF8.GetString(body);
Console.WriteLine("收到:" + message);
//消息响应
if (basicConsumer != null) basicConsumer.Model.BasicAck(args.DeliveryTag, false);
}
}
}
四.获取RabbitMQ日志
消费者
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using RabbitMQ.Client;
using RabbitMQ.Client.Events;
namespace RMQ_ReceiveLog
{
class Program
{
static void Main(string[] args)
{
string[] location = new string[]
{
"localhost",
"123.206.216.30"
};
var factory = new ConnectionFactory();
factory.HostName = location[1];
factory.UserName = "guest";
factory.Password = "guest";
var connection = factory.CreateConnection();
var channel = connection.CreateModel();
channel.QueueDeclare("ReceiveLog", false, false, true, null);//预先建立好消息队列
channel.QueueBind("ReceiveLog", "amq.rabbitmq.log", "error");
channel.QueueBind("ReceiveLog", "amq.rabbitmq.log", "warning");
channel.QueueBind("ReceiveLog", "amq.rabbitmq.log", "info");
var consumer=new EventingBasicConsumer(channel);
channel.BasicConsume("ReceiveLog", false, consumer);
channel.BasicQos(0, 1, false);//设置该客户在同一时间 RabbitMQ只发给该客户一个消息,在该客户没有响应消息之前不要给他分发消息将这条新的消息发送给下一个不那么忙碌的工作者。
consumer.Received += consumer_Received;
}
static void consumer_Received(object sender, BasicDeliverEventArgs args)
{
IBasicConsumer basicConsumer = sender as IBasicConsumer;
var body = args.Body;
string message = args.RoutingKey + " **" + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + "** " + Encoding.UTF8.GetString(body);
Console.WriteLine(message);
if (basicConsumer != null) basicConsumer.Model.BasicAck(args.DeliveryTag, false);//消息响应 确认消费者已收到消息
}
}
}
五.消息持久化
当RabbitMQ Server 关闭或者崩溃,那么里面存储的队列和消息默认是不会保存下来的。如果要让RabbitMQ保存住消息,需要在两个地方同时设置:需要保证队列和消息都是持久化的。
首先,要保证RabbitMQ不会丢失队列,所以要做如下设置:
bool durable = true;
channel.QueueDeclare("hello", durable, false, false, null);
虽然在语法上是正确的,但是在目前阶段是不正确的,因为我们之前已经定义了一个非持久化的hello
队列。RabbitMQ不允许我们使用不同的参数重新定义一个已经存在的同名队列,如果这样做就会报错。现在,定义另外一个不同名称的队列:
bool durable = true;
channel.queueDeclare("task_queue", durable, false, false, null);
queueDeclare
这个改动需要在发送端和接收端同时设置。
现在保证了task_queue
这个消息队列即使在RabbitMQ Server重启之后,队列也不会丢失。 然后需要保证消息也是持久化的, 这可以通过设置IBasicProperties.SetPersistent
为true
来实现:
var properties = channel.CreateBasicProperties();
properties.SetPersistent(true);
需要注意的是,将消息设置为持久化并不能完全保证消息不丢失。虽然他告诉RabbitMQ将消息保存到磁盘上,但是在RabbitMQ接收到消息和将其保存到磁盘上这之间仍然有一个小的时间窗口。 RabbitMQ 可能只是将消息保存到了缓存中,并没有将其写入到磁盘上。持久化是不能够一定保证的,但是对于一个简单任务队列来说已经足够。如果需要消息队列持久化的强保证,可以使用publisher confirms
生产者
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using RabbitMQ.Client;
namespace RMQ_Lasting_Send
{
class Program
{
static void Main(string[] args)
{
var factory = new ConnectionFactory();
factory.HostName = "localhost";
factory.UserName = "guest";
factory.Password = "guest";
using (var connection = factory.CreateConnection())
{
using (var channel = connection.CreateModel())
{
//不设置持久化的话在RabbitMQ Server关闭或者崩溃后重启 原来在服务里的消息会全部丢失掉 设置持久化可以避免这种情况
//我们之前已经定义了一个非持久化的`hello`队列。RabbitMQ不允许我们使用不同的参数重新定义一个已经存在的同名队列,如果这样做就会报错。现在,定义另外一个不同名称的队列:
channel.QueueDeclare("Lasting_queue", true, false, false, null);//要发送的信息 是否持久化 是否私有的 连接关闭时是否删除队列 参数
var properties = channel.CreateBasicProperties();
properties.SetPersistent(true); //设置消息持久化
while (true)
{
string message = GetMessage(args);
var body = Encoding.UTF8.GetBytes(message);
channel.BasicPublish("", "Lasting_queue", properties, body);//第一个参数是交换区的名字 第二个是消息队列的名字 第三个是参数 第四个是发送的信息
Console.WriteLine("发送:" + message);
}
}
}
}
private static string GetMessage(string[] args)
{
return Console.ReadLine();
}
}
}
消费者
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using RabbitMQ.Client;
using RabbitMQ.Client.Events;
namespace RMQ_Lasting_Receuve
{
class Program
{
static void Main(string[] args)
{
var factory = new ConnectionFactory();
factory.HostName = "localhost";
factory.UserName = "guest";
factory.Password = "guest";
using (var connection = factory.CreateConnection())
{
using (var channel = connection.CreateModel())
{
channel.QueueDeclare("Lasting_queue", true, false, false, null); //设置第二个参数为true 设置队列持久化
var consumer = new QueueingBasicConsumer(channel);
channel.BasicConsume("Lasting_queue", false, consumer);// 消息队列的名字 是否关闭消息响应 消费者的名字
while (true)
{
var ea = (BasicDeliverEventArgs)consumer.Queue.Dequeue();
var body = ea.Body;
var message = Encoding.UTF8.GetString(body);
int doit = message.Split(',').Length - 1;
Thread.Sleep(doit * 1000);
Console.WriteLine("接收端1:" + message + Environment.NewLine);
channel.BasicAck(ea.DeliveryTag, false);
}
}
}
}
}
}
六.消息响应
当处理一个比较耗时得任务的时候,也许想知道消费者(consumers)是否运行到一半就挂掉。在当前的代码中,当RabbitMQ将消息发送给消费者(consumers)之后,马上就会将该消息从队列中移除。
此时,如果把处理这个消息的工作者(worker)停掉,正在处理的这条消息就会丢失。同时,所有发送到这个工作者的还没有处理的消息都会丢失。
我们不想丢失任何任务消息。如果一个工作者(worker)挂掉了,我们希望该消息会重新发送给其他的工作者(worker)。
为了防止消息丢失,RabbitMQ提供了消息响应(acknowledgments
)机制。消费者会通过一个ack
(响应),告诉RabbitMQ已经收到并处理了某条消息,然后RabbitMQ才会释放并删除这条消息。
如果消费者(consumer
)挂掉了,没有发送响应,RabbitMQ就会认为消息没有被完全处理,然后重新发送给其他消费者(consumer)。这样,即使工作者(workers
)偶尔的挂掉,也不会丢失消息。
消息是没有超时这个概念的;当工作者与它断开连的时候,RabbitMQ会重新发送消息。这样在处理一个耗时非常长的消息任务的时候就不会出问题了。
总之就是有两个接收端receive1
和receive2
,由于RabbitMQ是轮询分发 receive1
收到第一个信息 receive2
收到第二个信息
下面receive1
会收到第三个信息 。。。。
但是当receive1
处理第三个信息时还没有处理完就 死掉了 那么 RabbitMQ就会把第三个信息发给receive2
,让receive2
去处理,这样就会避免信息的丢失
生产者
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using RabbitMQ.Client;
namespace RMQ_Ack_send
{
class Program
{
static void Main(string[] args)
{
var factory = new ConnectionFactory();
factory.HostName = "localhost";
factory.UserName = "guest";
factory.Password = "guest";
using (var connection = factory.CreateConnection())
{
using (var channel = connection.CreateModel())
{
channel.QueueDeclare("WorkQueues", false, false, false, null);
//var properties = channel.CreateBasicProperties();
//properties.DeliveryMode = 2;
while (true)
{
string message = GetMessage(args);
var body = Encoding.UTF8.GetBytes(message);
channel.BasicPublish("", "WorkQueues", null, body);
Console.WriteLine("发送:" + message);
}
}
}
}
private static string GetMessage(string[] args)
{
return Console.ReadLine();
}
}
}
消费者1
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using RabbitMQ.Client;
using RabbitMQ.Client.Events;
namespace RMQ_Ack_ReceiveOne
{
class Program
{
static void Main(string[] args)
{
var factory = new ConnectionFactory();
factory.HostName = "localhost";
factory.UserName = "guest";
factory.Password = "guest";
using (var connection = factory.CreateConnection())
{
using (var channel = connection.CreateModel())
{
channel.QueueDeclare("WorkQueues", false, false, false, null);
var consumer = new QueueingBasicConsumer(channel);
channel.BasicConsume("WorkQueues", false, consumer);// 消息队列的名字 是否关闭消息响应 消费者的名字
while (true)
{
var ea = (BasicDeliverEventArgs)consumer.Queue.Dequeue();
var body = ea.Body;
var message = Encoding.UTF8.GetString(body);
int doit = message.Split(',').Length - 1;
Thread.Sleep(doit*1000);
Console.WriteLine("接收端1:" + message + Environment.NewLine);
channel.BasicAck(ea.DeliveryTag, false);
}
}
}
}
}
}
消费者2
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using RabbitMQ.Client;
using RabbitMQ.Client.Events;
namespace RMQ_Ack_ReceiveSecond
{
class Program
{
static void Main(string[] args)
{
var factory = new ConnectionFactory();
factory.HostName = "localhost";
factory.UserName = "guest";
factory.Password = "guest";
using (var connection = factory.CreateConnection())
{
using (var channel = connection.CreateModel())
{
channel.QueueDeclare("WorkQueues", false, false, false, null);
var consumer = new QueueingBasicConsumer(channel);
channel.BasicConsume("WorkQueues", false, consumer);// 消息队列的名字 是否关闭消息响应 消费者的名字
while (true)
{
var ea = (BasicDeliverEventArgs)consumer.Queue.Dequeue();
var body = ea.Body;
var message = Encoding.UTF8.GetString(body);
int doit = message.Split('.').Length - 1;
Thread.Sleep(doit * 1000);
Console.WriteLine("接收端2:" + message + Environment.NewLine);
channel.BasicAck(ea.DeliveryTag, false);
}
}
}
}
}
}