C# 从多个队列读取,RabbitMQ
我是拉比犬的新手。当有多个队列(从中读取)时,我希望能够在不阻塞的情况下处理读取消息。有关于我如何做到这一点的信息吗 //编辑1C# 从多个队列读取,RabbitMQ,c#,.net,rabbitmq,amqp,C#,.net,Rabbitmq,Amqp,我是拉比犬的新手。当有多个队列(从中读取)时,我希望能够在不阻塞的情况下处理读取消息。有关于我如何做到这一点的信息吗 //编辑1 public class Rabbit : IMessageBus { private List<string> publishQ = new List<string>(); private List<string> subscribeQ = new List<string>(); Co
public class Rabbit : IMessageBus
{
private List<string> publishQ = new List<string>();
private List<string> subscribeQ = new List<string>();
ConnectionFactory factory = null;
IConnection connection = null;
IModel channel = null;
Subscription sub = null;
public void writeMessage( Measurement m1 ) {
byte[] body = Measurement.AltSerialize( m1 );
int msgCount = 1;
Console.WriteLine("Sending message to queue {1} via the amq.direct exchange.", m1.id);
string finalQueue = publishToQueue( m1.id );
while (msgCount --> 0) {
channel.BasicPublish("amq.direct", finalQueue, null, body);
}
Console.WriteLine("Done. Wrote the message to queue {0}.\n", m1.id);
}
public string publishToQueue(string firstQueueName) {
Console.WriteLine("Creating a queue and binding it to amq.direct");
string queueName = channel.QueueDeclare(firstQueueName, true, false, false, null);
channel.QueueBind(queueName, "amq.direct", queueName, null);
Console.WriteLine("Done. Created queue {0} and bound it to amq.direct.\n", queueName);
return queueName;
}
public Measurement readMessage() {
Console.WriteLine("Receiving message...");
Measurement m = new Measurement();
int i = 0;
foreach (BasicDeliverEventArgs ev in sub) {
m = Measurement.AltDeSerialize(ev.Body);
//m.id = //get the id here, from sub
if (++i == 1)
break;
sub.Ack();
}
Console.WriteLine("Done.\n");
return m;
}
public void subscribeToQueue(string queueName )
{
sub = new Subscription(channel, queueName);
}
public static string MsgSysName;
public string MsgSys
{
get
{
return MsgSysName;
}
set
{
MsgSysName = value;
}
}
public Rabbit(string _msgSys) //Constructor
{
factory = new ConnectionFactory();
factory.HostName = "localhost";
connection = factory.CreateConnection();
channel = connection.CreateModel();
//consumer = new QueueingBasicConsumer(channel);
System.Console.WriteLine("\nMsgSys: RabbitMQ");
MsgSys = _msgSys;
}
~Rabbit()
{
//observer??
connection.Dispose();
//channel.Dispose();
System.Console.WriteLine("\nDestroying RABBIT");
}
}
//附录2.cs
using System;
using System.IO;
using UtilityMeasurement;
using UtilityMessageBus;
public class MainClass
{
public static void Main()
{
//Asks for the message system
System.Console.WriteLine("\nEnter name of messageing system: ");
System.Console.WriteLine("Usage: [Rabbit] [Zmq]");
string MsgSysName = (System.Console.ReadLine()).ToString();
//Declare an IMessageBus instance:
//Here, an object of the corresponding Message System
// (ex. Rabbit, Zmq, etc) is instantiated
IMessageBus obj1 = MessageBusFactory.GetMessageBus(MsgSysName);
System.Console.WriteLine("\nA {0} object is now created.", MsgSysName);
//Create a new Measurement object m
Measurement m = new Measurement();
System.Console.WriteLine("Queue name to subscribe to: ");
string QueueName1 = (System.Console.ReadLine()).ToString();
obj1.subscribeToQueue( QueueName1 );
//Read message into m
m = obj1.readMessage();
if (m != null ) {
System.Console.WriteLine("\nMessage received from queue {0}:\n ID: {1}", m.id, m.id);
System.Console.WriteLine(" Time: {0}", m.time);
System.Console.WriteLine(" Value: {0}", m.value);
}
System.Console.WriteLine("Another queue name to subscribe to: ");
string QueueName2 = (System.Console.ReadLine()).ToString();
obj1.subscribeToQueue( QueueName2 );
m = obj1.readMessage();
if (m != null ) {
System.Console.WriteLine("\nMessage received from queue {0}:\n ID: {1}", m.id, m.id);
System.Console.WriteLine(" Time: {0}", m.time);
System.Console.WriteLine(" Value: {0}", m.value);
}
obj1.disposeAll();
}
}
两个信息来源:
- %程序文件%\RabbitMQ\DotNetClient\examples\src(基本示例)
- 从Mercurial存储库(c#项目)获取完整的工作示例
- 声明/断言/侦听/订阅/发布
问答 见: 问:您能否使用新订阅(频道、队列名称)订阅多个队列 对。可以使用绑定键,例如abc.*.hij或abc.#.hij,也可以附加多个绑定。前者假设您已经围绕某种对您有意义的原则设计了路由密钥(请参阅常见问题解答中的路由密钥)。对于后者,您需要绑定到多个队列 手动实现n绑定。 见: 这个模式背后没有太多代码,所以如果通配符不够,您可以使用自己的订阅模式。您可以从此类继承并为其他绑定添加另一个方法。。。这可能会起作用,或者类似的(未经测试) AQMP规范规定可以进行多种手动绑定: 如果是这样,我如何遍历所有订阅的队列并返回消息(如果没有消息,则返回null) 当有消息可用时,订阅者会通知您。否则,您所描述的是一个拉接口,在该接口中,您可以根据请求向下拉消息。如果没有可用的消息,您将得到一个空值。顺便说一句:Notify方法可能更方便 哦,请注意,所有这些操作都有不同的方法。我将编辑我的帖子以反映代码 实时代码: 此版本必须使用通配符订阅多个路由密钥 n使用订阅的手动路由密钥留给读者作为练习。;-)我想你还是倾向于拉界面。顺便说一句:拉接口的效率低于通知接口
using (Subscription sub = new Subscription(ch, QueueNme))
{
foreach (BasicDeliverEventArgs ev in sub)
{
Process(ev.Body);
...
注意:foreach使用IEnumerable,IEnumerable包装通过“yield”语句到达新消息的事件。实际上,这是一个无限循环
---更新
AMQP的设计理念是将TCP连接数保持在与应用程序数相同的低水平,这意味着每个连接可以有多个通道
这个问题中的代码(编辑3)尝试使用两个订阅服务器和一个通道,而它应该(我相信)是每个线程每个通道一个订阅服务器,以避免锁定问题。建议:使用路由键“通配符”。可以使用java客户端订阅多个不同的队列名称,但据我所知,.net客户端没有在Subscriber helper类中实现这一点
如果在同一订阅线程上确实需要两个不同的队列名称,则建议对.net使用以下拉取序列:
using (IModel ch = conn.CreateModel()) { // btw: no reason to close the channel afterwards IMO
conn.AutoClose = true; // no reason to closs the connection either. Here for completeness.
ch.QueueDeclare(queueName);
BasicGetResult result = ch.BasicGet(queueName, false);
if (result == null) {
Console.WriteLine("No message available.");
} else {
ch.BasicAck(result.DeliveryTag, false);
Console.WriteLine("Message:");
}
return 0;
}
--更新2:
从RabbitMQ列表:
“假设元素.Next()阻塞了其中一个订阅。
您可以从每个订阅中检索传递,超时时间为
读过去。或者你可以设置一个队列来接收
所有的测量和检索信息,从它与一个单一的订阅。”(埃米尔)
这意味着,当第一个队列为空时,.Next()阻塞等待下一条消息出现。i、 e.订户内置了等待下一条消息
--更新3:
在.net下,使用QueueingBasicConsumer从多个队列进行消费
实际上,这里有一条关于它的线索,可以让你了解它的用法:
--更新4:
有关.QueueingBasicConsumer的更多信息
这里有一个示例代码
示例通过一些修改复制到答案中(请参见//最简单的方法是使用EventingBasicConsumer。我的网站上有一个关于如何使用它的示例
此使用者类公开您可以使用的已接收事件,因此不会阻止。其余代码基本保持不变。非常感谢您的反馈。我仍在学习消息传递系统,有些操作我仍然不理解。例如,听。我还看到了rabbitmq如何订阅队列。您可以订阅吗使用新订阅(通道、队列名称)发送到多个队列?如果是,如何遍历所有订阅的队列并返回消息(如果没有消息,则返回null)?哦,请注意,我用不同的方法进行了所有这些操作。我将编辑我的帖子以反映代码。再次感谢。我编辑了上面订阅和编写函数的代码。但是,我有这个ru
using System;
using System.IO;
using UtilityMeasurement;
using UtilityMessageBus;
public class MainClass
{
public static void Main()
{
//Asks for the message system
System.Console.WriteLine("\nEnter name of messageing system: ");
System.Console.WriteLine("Usage: [Rabbit] [Zmq]");
string MsgSysName = (System.Console.ReadLine()).ToString();
//Declare an IMessageBus instance:
//Here, an object of the corresponding Message System
// (ex. Rabbit, Zmq, etc) is instantiated
IMessageBus obj1 = MessageBusFactory.GetMessageBus(MsgSysName);
System.Console.WriteLine("\nA {0} object is now created.", MsgSysName);
//Create a new Measurement object m
Measurement m = new Measurement();
System.Console.WriteLine("Queue name to subscribe to: ");
string QueueName1 = (System.Console.ReadLine()).ToString();
obj1.subscribeToQueue( QueueName1 );
//Read message into m
m = obj1.readMessage();
if (m != null ) {
System.Console.WriteLine("\nMessage received from queue {0}:\n ID: {1}", m.id, m.id);
System.Console.WriteLine(" Time: {0}", m.time);
System.Console.WriteLine(" Value: {0}", m.value);
}
System.Console.WriteLine("Another queue name to subscribe to: ");
string QueueName2 = (System.Console.ReadLine()).ToString();
obj1.subscribeToQueue( QueueName2 );
m = obj1.readMessage();
if (m != null ) {
System.Console.WriteLine("\nMessage received from queue {0}:\n ID: {1}", m.id, m.id);
System.Console.WriteLine(" Time: {0}", m.time);
System.Console.WriteLine(" Value: {0}", m.value);
}
obj1.disposeAll();
}
}
using (Subscription sub = new Subscription(ch, QueueNme))
{
foreach (BasicDeliverEventArgs ev in sub)
{
Process(ev.Body);
...
using (IModel ch = conn.CreateModel()) { // btw: no reason to close the channel afterwards IMO
conn.AutoClose = true; // no reason to closs the connection either. Here for completeness.
ch.QueueDeclare(queueName);
BasicGetResult result = ch.BasicGet(queueName, false);
if (result == null) {
Console.WriteLine("No message available.");
} else {
ch.BasicAck(result.DeliveryTag, false);
Console.WriteLine("Message:");
}
return 0;
}
IModel channel = ...;
QueueingBasicConsumer consumer = new QueueingBasicConsumer(channel);
channel.BasicConsume(queueName, false, null, consumer); //<-----
channel.BasicConsume(queueName2, false, null, consumer); //<-----
// etc. channel.BasicConsume(queueNameN, false, null, consumer); //<-----
// At this point, messages will be being asynchronously delivered,
// and will be queueing up in consumer.Queue.
while (true) {
try {
BasicDeliverEventArgs e = (BasicDeliverEventArgs) consumer.Queue.Dequeue();
// ... handle the delivery ...
channel.BasicAck(e.DeliveryTag, false);
} catch (EndOfStreamException ex) {
// The consumer was cancelled, the model closed, or the
// connection went away.
break;
}
}
ch.QueueDeclare(queueName);
BasicGetResult result = ch.BasicGet(queueName, false);
if (result == null) {
Console.WriteLine("No message available.");
} else {
ch.BasicAck(result.DeliveryTag, false);
Console.WriteLine("Message:");
// deserialize body and display extra info here.
}