C# 正在阅读启动前发送的消息?

C# 正在阅读启动前发送的消息?,c#,rabbitmq,C#,Rabbitmq,Erlang RMQ服务器不间断地运行 假设我有一个RMQ接收器和RMQ发送器,它从一开始就发送消息 当我启动它们时:接收者第一,发送者第二,消息被发送,服务器接收它 但当我首先启动发送方,在它发送消息之后,我启动接收方,接收方并没有看到那个消息 我的问题是RMQ是否能够处理(读取)第二种情况下的消息,如果是,需要哪些选项?交换已经是持久的,但它没有帮助。简单的生产者 // producer static void Main( string[] args ) {

Erlang RMQ服务器不间断地运行

假设我有一个RMQ接收器和RMQ发送器,它从一开始就发送消息

当我启动它们时:接收者第一,发送者第二,消息被发送,服务器接收它

但当我首先启动发送方,在它发送消息之后,我启动接收方,接收方并没有看到那个消息

我的问题是RMQ是否能够处理(读取)第二种情况下的消息,如果是,需要哪些选项?交换已经是持久的,但它没有帮助。

简单的生产者

    // producer
    static void Main( string[] args )
    {
        var factory = new ConnectionFactory() 
        { 
            HostName = "localhost"                
        };
        using ( var connection = factory.CreateConnection() )
        {
            using ( var channel = connection.CreateModel() )
            {
                channel.QueueDeclare( "hello", true, false, false, null );

                string message = "Hello World!";
                var body = Encoding.UTF8.GetBytes( message );

                while ( true )
                {
                    Console.WriteLine( "Press key to send message" );
                    Console.ReadLine();

                    channel.BasicPublish( "", "hello", null, body );

                    Console.WriteLine( " [x] Sent {0}", message );
                }
            }
        }
我运行这个,发布了一些消息,我在RMQ上看到它们都在一个队列中

然后我运行这个简单的消费者

    // consumer
    static void Main( string[] args )
    {
        var factory = new ConnectionFactory() { HostName = "localhost" };
        using (var connection = factory.CreateConnection())
        {
            using (var channel = connection.CreateModel())
            {
                channel.QueueDeclare("hello", true, false, false, null);

                var consumer = new QueueingBasicConsumer(channel);
                channel.BasicConsume("hello", true, consumer);

                Console.WriteLine(" [*] Waiting for messages." +
                                         "To exit press CTRL+C");
                while (true)
                {
                    var ea = (BasicDeliverEventArgs)consumer.Queue.Dequeue();

                    var body    = ea.Body;
                    var message = Encoding.UTF8.GetString(body);
                    Console.WriteLine(" [x] Received {0}", message);
                }
            }
        }
    }
我在消费者中得到了我的信息,即使它是在生产者完成后运行的

请验证这与您的设置有何不同

编辑:如果生产者中有支持队列的exchange,此操作也有效:

    // producer
    static void Main( string[] args )
    {
        var factory = new ConnectionFactory() 
        { 
            HostName = "localhost"                
        };
        using ( var connection = factory.CreateConnection() )
        {
            using ( var channel = connection.CreateModel() )
            {
                channel.QueueDeclare( "hello", true, false, false, null );
                channel.ExchangeDeclare( "helloe", "fanout", true );
                channel.QueueBind( "hello", "helloe", "" );

                string message = "Hello World!";
                var body = Encoding.UTF8.GetBytes( message );

                while ( true )
                {
                    Console.WriteLine( "Press key to send message" );
                    Console.ReadLine();

                    channel.BasicPublish( "helloe", "", null, body );

                    Console.WriteLine( " [x] Sent {0}", message );
                }
            }
        }

        Console.WriteLine( "finished" );
        Console.ReadLine();
    }
(无需更改耗电元件)

编辑2:这在使用事件消费者时也有效:

    static void Main( string[] args )
    {
        var factory = new ConnectionFactory() { HostName = "localhost" };
        using (var connection = factory.CreateConnection())
        {
            using (var channel = connection.CreateModel())
            {
                channel.QueueDeclare("hello", true, false, false, null);

                var consumer = new EventingBasicConsumer(channel);
                consumer.Received += (s, e) =>
                {
                    var message = Encoding.UTF8.GetString(e.Body);
                    Console.WriteLine(" [x] Received {0}", message);
                };
                channel.BasicConsume("hello", true, consumer);

                Console.WriteLine(" [*] Waiting for messages." +
                                         "To exit press CTRL+C");

                Console.ReadLine();
            }
        }
    }

,RabbitMQ能够保留这些消息,直到您的消费者可用为止。这只是您何时声明队列和队列配置的问题

简言之;如果在发布消息之前声明并绑定队列,则消息将保留在该队列中,而不管是否有使用者

例如,在声明队列时,某些参数会影响此行为:

  • exclusive
    ,如果为true,将在使用者断开连接时删除队列(和消息)
  • 持久性
    ,如果为true,则即使RabbitMQ重新启动,也会保留消息
当使用者在启动时以幂等方式创建和设置自己的队列时,情况与您描述的完全相同;如果消费者从未运行过,则消息会“丢失”

这在某种程度上是一种常见做法,您可以通过教程进行验证,尤其是在出版商不知道消费者或他们需要什么队列的情况下


如果您确实想确保所有消息都已收到,则需要一些事先声明队列的方法。

如果客户机先启动并尝试发送消息,但没有服务器侦听TCP 5672,那么客户机将如何成功传递消息?从客户机的角度来看,没有通信的另一端——服务器可以在一秒钟、一分钟、一年内启动,甚至永远不会启动。如果我理解正确,客户端将必须维护自己的未送达邮件日志,当服务器启动时,客户端应首先发送未送达的邮件,然后才发送连续的邮件。@WiktorZychla,啊,对不起,选择我的文字是不幸的,在最初的问题中我使用了名称“服务器/客户端”在我的程序中这些部分的角色。我改变了问题,改为使用“receiver/sender”,另一方面,RMQ(Erlang服务器)的核心/引擎不间断运行,这就是我知道消息正确发送的原因。再一次为困惑感到抱歉。另一方面,这似乎很容易,而且对我来说总是有效的。我甚至有一个简单的例子,我运行生产者,发布消息,我看到消息在队列中等待,我关闭生产者。我运行consumer,它会使用队列中的所有消息。@WiktorZychla,好吧,好消息,它应该可以工作了。您还记得此场景中的任何特定选项吗?将发布一个简短的答案供您验证。很好,我看到了第一个区别,您不声明交换,另一方面,我声明为持久交换,但不是队列。测试时间!:-)非常感谢。当我有一个交易所支持队列时,这也起作用。事实上,我已经去掉了我原来的例子。编辑了我的答案。到目前为止,唯一的区别是使用
QueueingBasicConsumer
vs
EventingBasicConsumer
,在后一种情况下,初始消息(在消费者启动之前发送)丢失。仍在调查…@astrowalker:有趣的是,当我切换到
EventingBasicConsumer
时,这似乎仍然有效。非常感谢你的帮助,这一次是我愚蠢的改变顺序,我写了消费然后订阅:-(再次感谢你,谜团解决了,现在一切都在我这边工作了。