C#终端的说明文档: http://www.rabbitmq.com/dotnet-api-guide.html

这里介绍使用RabbitMQ的几种典型场景。

1. 简单direct模式( http://www.rabbitmq.com/tutorials/tutorial-one-dotnet.html)。生产者发送消息到一个队列,消费者从队列读取消息。这是最简单的使用场景,下面的代码使用默认exchange,消息自动确认。注意后台接收消息的线程完成前不要关闭连接,这里消费者是通过Console.ReadLine();保证连接不会Dispose。

生产者:

public static void test1()
{
    var factory = new ConnectionFactory() { HostName = "localhost" };
    using (var connection = factory.CreateConnection())
    using (var channel = connection.CreateModel())
    {
        channel.QueueDeclare(queue: "hello",
                             durable: false,
                             exclusive: false,
                             autoDelete: false,
                             arguments: null);

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

channel.BasicPublish(exchange: "",
                             routingKey: "hello",
                             basicProperties: null,
                             body: body);
        Console.WriteLine(" [x] Sent {0}", message);
    }

Console.WriteLine(" Press [enter] to exit.");
    Console.ReadLine();
}

消费者

public static void test1()
{
    var factory = new ConnectionFactory() { HostName = "localhost" };
    using (var connection = factory.CreateConnection())
    using (var channel = connection.CreateModel())
    {
        channel.QueueDeclare(queue: "hello",
                             durable: false,
                             exclusive: false,
                             autoDelete: false,
                             arguments: null);

var consumer = new EventingBasicConsumer(channel);
        consumer.Received += (model, ea) =>
        {
            var body = ea.Body;
            var message = Encoding.UTF8.GetString(body);
            Console.WriteLine(" [x] Received {0}", message);
        };
        channel.BasicConsume(queue: "hello",
                             noAck: true,
                             consumer: consumer);

Console.WriteLine(" Press [enter] to exit.");
        Console.ReadLine();
    }
}

2. 多个消费者连接队列(http://www.rabbitmq.com/tutorials/tutorial-two-dotnet.html)。使用场景:生产者发送比较耗时的任务,多个消费者从队列获取任务,完成计算。优点:方便系统扩展,添加消费者即可增加系统的负载能力,通过显式消息确认、prefetch消息量的控制,可以实现多个消费者之间的负载均衡。prefetch N的意思是在消费者确认前,只发送N个消息,也就是等待确认的消息最多N个(默认不设,队列的消息会全部发给消费者,然后等待确认),只要客户端的连接保持,便不会重发,如果连接中断,消息还是没有确认,则会重新发送。

生产者代码和前一个例子类似,这里只给出消费者代码

public static void test2()
{
    var factory = new ConnectionFactory() { HostName = "localhost" };
    using (var connection = factory.CreateConnection())
    using (var channel = connection.CreateModel())
    {
        channel.QueueDeclare(queue: "task_queue",
                             durable: true,
                             exclusive: false,
                             autoDelete: false,
                             arguments: null);

channel.BasicQos(prefetchSize: 0, prefetchCount: 1, global: false);

Console.WriteLine(" [*] Waiting for messages.");

var consumer = new EventingBasicConsumer(channel);
        consumer.Received += (model, ea) =>
        {
            var body = ea.Body;
            var message = Encoding.UTF8.GetString(body);
            Console.WriteLine(" [x] Received {0}", message);

int dots = message.Split('.').Length - 1;
            Thread.Sleep(dots * 10000);

Console.WriteLine(" [x] Done");

channel.BasicAck(deliveryTag: ea.DeliveryTag, multiple: false);
        };
        channel.BasicConsume(queue: "task_queue",
                             noAck: false,
                             consumer: consumer);

Console.WriteLine(" Press [enter] to exit.");
        Console.ReadLine();
    }
}

3. 订阅发布模式(http://www.rabbitmq.com/tutorials/tutorial-three-dotnet.html)。exchange使用fanout模式。注意下面代码创建了命名队列(通过队列名可以方便标识消费者),如果队列不需要持久化,也可以使用临时队列(queueName = channel.QueueDeclare().QueueName;),RabbitMQ为队列分配一个唯一标识,消费者断开后会自动删除队列。

生产者:

public static void test3(string[] args)
{
    var factory = new ConnectionFactory() { HostName = "localhost" };
    using (var connection = factory.CreateConnection())
    using (var channel = connection.CreateModel())
    {
        channel.ExchangeDeclare("logs", "fanout");

for (int i = 0; i < args.Length; i++)
        {
            var message = "task_queue_t3";
            var body = Encoding.UTF8.GetBytes(message);

var properties = channel.CreateBasicProperties();
            properties.SetPersistent(true);

channel.BasicPublish(exchange: "logs", routingKey: "", basicProperties: properties, body: body);
            Console.WriteLine(" [x] Sent {0}", message);
        }

}
}

消费者:

public static void test3()
{
    var factory = new ConnectionFactory() { HostName = "localhost" };
    using (var connection = factory.CreateConnection())
    using (var channel = connection.CreateModel())
    {
        channel.ExchangeDeclare("logs", ExchangeType.Fanout);

string queueName = "task_queue_t3";

Console.WriteLine(Encoding.UTF8.GetBytes(queueName).Length);

channel.QueueDeclare(queue: queueName,
             durable: true,
             exclusive: true,
             autoDelete: true,
             arguments: null);
        //queueName = channel.QueueDeclare().QueueName;

channel.QueueBind(queue: queueName, exchange: "logs", routingKey: "");

Console.WriteLine(" [*] Waiting for messages.");

var consumer = new EventingBasicConsumer(channel);
        consumer.Received += (model, ea) =>
        {
            var body = ea.Body;
            var message = Encoding.UTF8.GetString(body);
            Console.WriteLine(" [x] Received {0}", message);

int dots = message.Split('.').Length - 1;
            Thread.Sleep(dots * 1000);

Console.WriteLine(" [x] Done");

channel.BasicAck(deliveryTag: ea.DeliveryTag, multiple: false);
        };
        channel.BasicConsume(queue: queueName,
                             noAck: false,
                             consumer: consumer);

Console.WriteLine(" Press [enter] to exit.");
        Console.ReadLine();
    }
}

4. 路由(http://www.rabbitmq.com/tutorials/tutorial-four-dotnet.html)。exchange使用Direct模式,通过binding key 精确匹配routing key选择消息路由。可以有多个binding key。

生产者:

channel.ExchangeDeclare("direct_logs", "direct");

channel.BasicPublish(exchange: "direct_logs", routingKey: "info", basicProperties: properties, body: body);

消费者:

channel.ExchangeDeclare("direct_logs", "direct");

string queueName = channel.QueueDeclare().QueueName;

channel.QueueBind(queueName, "direct_logs", "info");
channel.QueueBind(queueName, "direct_logs", "error");

5. Topic模式(http://www.rabbitmq.com/tutorials/tutorial-five-dotnet.html)。exchange使用Topic模式,可以实现模糊匹配。

生产者:

channel.ExchangeDeclare("topic_logs", ExchangeType.Topic);

channel.BasicPublish(exchange: "topic_logs", routingKey: "lazy.green.cat", basicProperties: properties, body: body);

消费者:

channel.ExchangeDeclare("topic_logs", "topic");

string queueName = "Q2";
channel.QueueDeclare(queue: queueName,
     durable: true,
     exclusive: true,
     autoDelete: true,
     arguments: null);

channel.QueueBind(queueName, "topic_logs", "*.*.rabbit");
channel.QueueBind(queueName, "topic_logs", "lazy.#");

6. 远程过程调用RPC(http://www.rabbitmq.com/tutorials/tutorial-six-dotnet.html)。实现客户和服务之间的通信。一次通信过程如下:

  • 客户端发送请求消息。客户端发送请求时通过reply_to指定回复的地址(回复的queue,由于RPC的特殊性,我们使用默认的exchange来做路由,这时候queue名字便是路由键)和correlation_id(标记发送的消息,回复的时候通过这个ID来确认回复的是哪个请求)。在reply_to的queue上等待回复。
  • 服务器收到请求,处理后发送回复到默认exchange,用请求消息的reply_to做路由键,这样回复便发到了reply_to指定的queue。设置的回复消息的correlation_id=请求消息的correction_id。
  • 客户端在reply_to的队列上收到回复。
  • 通过ack和prefetch N控制同步。

RPCServer端代码:

public static void RPCServer()
        {
            var factory = new ConnectionFactory() { HostName = "localhost" };
            using (var connection = factory.CreateConnection())
            using (var channel = connection.CreateModel())
            {
                channel.QueueDeclare(queue: "rpc_queue",
                                     durable: false,
                                     exclusive: false,
                                     autoDelete: false,
                                     arguments: null);
                channel.BasicQos(0, 1, false);
                var consumer = new QueueingBasicConsumer(channel);
                channel.BasicConsume(queue: "rpc_queue",
                                     noAck: false,
                                     consumer: consumer);
                Console.WriteLine(" [x] Awaiting RPC requests");

while (true)
                {
                    string response = null;
                    var ea = (BasicDeliverEventArgs)consumer.Queue.Dequeue();

var body = ea.Body;
                    var props = ea.BasicProperties;
                    var replyProps = channel.CreateBasicProperties();
                    replyProps.CorrelationId = props.CorrelationId;

try
                    {
                        var message = Encoding.UTF8.GetString(body);
                        int n = int.Parse(message);
                        Console.WriteLine(" [.] fib({0})", message);
                        response = "abc"; //do time consuming work here
                    }
                    catch (Exception e)
                    {
                        Console.WriteLine(" [.] " + e.Message);
                        response = "";
                    }
                    finally
                    {
                        var responseBytes = Encoding.UTF8.GetBytes(response);
                        channel.BasicPublish(exchange: "",
                                             routingKey: props.ReplyTo,
                                             basicProperties: replyProps,
                                             body: responseBytes);
                        channel.BasicAck(deliveryTag: ea.DeliveryTag,
                                         multiple: false);
                    }
                }
            }
        }

客户端代码:

class RPCClient
    {
        private IConnection connection;
        private IModel channel;
        private string replyQueueName;
        private QueueingBasicConsumer consumer;

public RPCClient()
        {
            var factory = new ConnectionFactory() { HostName = "localhost" };
            connection = factory.CreateConnection();
            channel = connection.CreateModel();
            replyQueueName = channel.QueueDeclare().QueueName;
            consumer = new QueueingBasicConsumer(channel);
            channel.BasicConsume(queue: replyQueueName,
                                 noAck: true,
                                 consumer: consumer);
        }

public string Call(string message)
        {
            var corrId = Guid.NewGuid().ToString();
            var props = channel.CreateBasicProperties();
            props.ReplyTo = replyQueueName;
            props.CorrelationId = corrId;

var messageBytes = Encoding.UTF8.GetBytes(message);
            channel.BasicPublish(exchange: "",
                                 routingKey: "rpc_queue",
                                 basicProperties: props,
                                 body: messageBytes);

while (true)
            {
                var ea = (BasicDeliverEventArgs)consumer.Queue.Dequeue();
                if (ea.BasicProperties.CorrelationId == corrId)
                {
                    return Encoding.UTF8.GetString(ea.Body);
                }
            }
        }

public void Close()
        {
            connection.Close();
        }
    }

//测试

public static void RPCTest()
{
    var rpcClient = new RPCClient();

Console.WriteLine(" [x] Requesting fib(30)");
    var response = rpcClient.Call("30");
    Console.WriteLine(" [.] Got '{0}'", response);

rpcClient.Close();
}

RabbitMQ介绍4 - 编程(C#客户端示例)的更多相关文章

  1. RabbitMQ介绍

    (一)RabbitMQ基本概念 RabbitMQ是流行的开源消息队列系统,用erlang语言开发.我曾经对这门语言挺有兴趣,学过一段时间,后来没坚持.RabbitMQ是 AMQP(高级消息队列协议)的 ...

  2. 《Objective-C编程》部分示例

    <Objective-C编程>部分示例 最近在看<Objective-C编程>顺带实现了书中部分示例代码.如果感兴趣可以自行 下载(点我). 通过本书大致了解了Objectiv ...

  3. 牛客网Java刷题知识点之TCP、UDP、TCP和UDP的区别、socket、TCP编程的客户端一般步骤、TCP编程的服务器端一般步骤、UDP编程的客户端一般步骤、UDP编程的服务器端一般步骤

    福利 => 每天都推送 欢迎大家,关注微信扫码并加入我的4个微信公众号:   大数据躺过的坑      Java从入门到架构师      人工智能躺过的坑         Java全栈大联盟   ...

  4. Python学习笔记(二)网络编程的简单示例

    Python中的网络编程比C语言中要简洁很多,毕竟封装了大量的细节. 所以这里不再介绍网络编程的基本知识.而且我认为,从Python学习网络编程不是一个明智的选择.   简单的TCP连接 服务器代码如 ...

  5. .net RabbitMQ 介绍、安装、运行

    RabbitMQ介绍 什么是MQ Message Queue(简称:MQ),消息队列 顾名思义将内容存入到队列中,存入取出的原则是先进先出.后进后出. 其主要用途:不同进程Process/线程Thre ...

  6. Socket网络编程--FTP客户端

    Socket网络编程--FTP客户端(1)(Windows) 已经好久没有写过博客进行分享了.具体原因,在以后说. 这几天在了解FTP协议,准备任务是写一个FTP客户端程序.直接上干货了. 0.了解F ...

  7. C# WebSocket 服务端示例代码 + HTML5客户端示例代码

    WebSocket服务端 C#示例代码 using System; using System.Collections.Generic; using System.Linq; using System. ...

  8. 二维码(2)二维码登录原理及Android客户端示例

    1,原理 服务器: 数据库: 建立一个2维码登录的数据表,产生一个登录页时,插入一条记录X,X含将要登录的用户名字段(初始为空),2维码中的数据字段(唯一) 登录页面: 在产生的2维码中包含关键数据Y ...

  9. linux 网络编程:客户端与服务器通过TCP协议相互通信 + UDP

    1.TCP编程的客户端一般步骤: 1.创建一个socket,用函数socket(): 2.设置socket属性,用函数setsockopt():* 可选: 3.绑定IP地址.端口等信息到socket上 ...

随机推荐

  1. 越狱Season 1-Episode 8: The Old Head

    Season 1, Episode 8: The Old Head -Michael: 17 days from now they strap my brother to an electric ch ...

  2. Linux下串口与工业协议的开发

    1.串口通信原理 串口通信定义 串口通信:数据的串行传送方式.串口通信可分为同步通信与异步通信. 同步通信:按照软件识别同步字符来实现数据的发送和接收. 将许多字符组成一个信息组进行发送 要求发送时钟 ...

  3. cve-2015-1635 poc

    import socket import random ipAddr = "10.1.89.20" hexAllFfff = " req1 = "GET / H ...

  4. java多线程:并发包中的信号量和计数栓的编程模型

    一:信号量的编程模型 package com.yeepay.sxf.test.atomic.test; import java.util.concurrent.Semaphore; /** * 测试信 ...

  5. Dtrace for Linux 2016

    http://www.brendangregg.com/blog/2016-10-27/dtrace-for-linux-2016.html

  6. WaitAny, WaitAll 和 SignalAndWait

    除了Set 和 WaitOne方法外,在类WaitHandle中还有一些用来创建复杂的同步过程的静态方法. WaitAny, WaitAll 和 SignalAndWait使跨多个可能为不同类型的等待 ...

  7. windows7旗舰版激活密钥永久版免费分享

    windows7之家不仅提供精品Win7教程 给大家,加上这个windows7激活密匙还帮大家解决windows7系统激活问题,包括win7旗舰版 windows7安装版这些. 用的是Windows7 ...

  8. PgSQL · 特性分析 · 谈谈checkpoint的调度

    在PG的众多参数中,参数checkpoint相关的几个参数颇为神秘.这些参数与checkpoint的调度有关,对系统的稳定性还是比较重要的,下面我们为大家解析一下,这要先从PG的数据同步机制谈起. P ...

  9. Concurrent inserts on MyISAM and the binary log

    Recently I had an interesting surprise with concurrent inserts into a MyISAM table. The inserts were ...

  10. image

    copy /B 1.jpg+2.jpg new.jpg 生成图用Stegsolve的file format查看文件格式 附带上一些图片格式的幻数,方便查阅.PNG = ‰PNG (89504E47)G ...