RabbitMQ介绍4 - 编程(C#客户端示例)
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#客户端示例)的更多相关文章
- RabbitMQ介绍
(一)RabbitMQ基本概念 RabbitMQ是流行的开源消息队列系统,用erlang语言开发.我曾经对这门语言挺有兴趣,学过一段时间,后来没坚持.RabbitMQ是 AMQP(高级消息队列协议)的 ...
- 《Objective-C编程》部分示例
<Objective-C编程>部分示例 最近在看<Objective-C编程>顺带实现了书中部分示例代码.如果感兴趣可以自行 下载(点我). 通过本书大致了解了Objectiv ...
- 牛客网Java刷题知识点之TCP、UDP、TCP和UDP的区别、socket、TCP编程的客户端一般步骤、TCP编程的服务器端一般步骤、UDP编程的客户端一般步骤、UDP编程的服务器端一般步骤
福利 => 每天都推送 欢迎大家,关注微信扫码并加入我的4个微信公众号: 大数据躺过的坑 Java从入门到架构师 人工智能躺过的坑 Java全栈大联盟 ...
- Python学习笔记(二)网络编程的简单示例
Python中的网络编程比C语言中要简洁很多,毕竟封装了大量的细节. 所以这里不再介绍网络编程的基本知识.而且我认为,从Python学习网络编程不是一个明智的选择. 简单的TCP连接 服务器代码如 ...
- .net RabbitMQ 介绍、安装、运行
RabbitMQ介绍 什么是MQ Message Queue(简称:MQ),消息队列 顾名思义将内容存入到队列中,存入取出的原则是先进先出.后进后出. 其主要用途:不同进程Process/线程Thre ...
- Socket网络编程--FTP客户端
Socket网络编程--FTP客户端(1)(Windows) 已经好久没有写过博客进行分享了.具体原因,在以后说. 这几天在了解FTP协议,准备任务是写一个FTP客户端程序.直接上干货了. 0.了解F ...
- C# WebSocket 服务端示例代码 + HTML5客户端示例代码
WebSocket服务端 C#示例代码 using System; using System.Collections.Generic; using System.Linq; using System. ...
- 二维码(2)二维码登录原理及Android客户端示例
1,原理 服务器: 数据库: 建立一个2维码登录的数据表,产生一个登录页时,插入一条记录X,X含将要登录的用户名字段(初始为空),2维码中的数据字段(唯一) 登录页面: 在产生的2维码中包含关键数据Y ...
- linux 网络编程:客户端与服务器通过TCP协议相互通信 + UDP
1.TCP编程的客户端一般步骤: 1.创建一个socket,用函数socket(): 2.设置socket属性,用函数setsockopt():* 可选: 3.绑定IP地址.端口等信息到socket上 ...
随机推荐
- 布局转换:文档流->绝对定位
布局转换:文档流->绝对定位(详见妙味JS高级教程,运动课程第6课20分钟起)比如一个DIV中有三张图片并排,个数不确定的布局.需要鼠标移上去图片从中心放大,只使用float:left布局在放大 ...
- caffe:编译时提示:unsupported GNU version! gcc versions later than 4.9 are not supported!
NVCC src/caffe/solvers/adam_solver.cuIn file included from /usr/local/cuda/include/cuda_runtime.h:76 ...
- Unity光照
广义地说,Unity有2种光源.1.动态光源 2.Backed Lighting 1.动态光源 就是实时计算的.只要摆光源就可以了 2.Backed Lighting 提前处理好光照贴图.贴在物体上 ...
- 内网渗透中的反弹Shell与端口转发
from:https://www.91ri.org/9367.html Web渗透中的反弹Shell与端口转发 php需未禁用exec函数一:生成php反弹脚本msf > msfpayload ...
- playframework1.x的eclipse插件开源-playtools
playtools介绍 playframework(1.2.x)是一款令人兴奋的java restful风格的web框架,使用它已经有两年多. 其中结合eclipse开发项目往往要不断进行cmd窗口切 ...
- 【转】越狱的 iPhone、iPad 通过网站实现一键安装 ipa 格式的 APP 应用
1.已经越狱的 iPhone.iPad 设备,当通过其自带的 safari 浏览器访问 ipa 应用下载网站时,利用 itms-services 协议,可以一键安装 ipa 文件的 iOS 应用,例如 ...
- Android ListView 第一次设置Adapter时候getView调用多次
之前遇到这个奇怪现象,记录一下: 使用Listview并设置Adapter时, 会回调多次getView,比如我有4个items,按理说getView应该是调用一次(打出4个log),结果回调有4次( ...
- Oracle序列使用:建立、删除
转自:http://www.cnblogs.com/WangPB/archive/2010/07/13/1776766.html 在开始讲解Oracle序列使用方法之前,先加一点关于Oracle cl ...
- Android 网络编程--URL互联网资源
1.加入权限 <uses-permission android:name="android.permission.INTERNET"/> 2.Layout设计 < ...
- Hub, bridge, switch, router, gateway的区别
这些概念性的东西,其实,有的区别不是很大,有的区别很大. Hub 就是一个重复转发器,就是从一个port接受到数据后,就会原样的向其他的所有端口发送刚才收到的数据.个人理解为是工作在物理层的东西.但是 ...





