孤独将会是人生中遇见的最大困难。

实体类:

DocumentType.cs

  public enum DocumentType
{
//日志
Journal = 1,
//论文
Thesis = 2,
//会议文件
Meeting = 3
}

MessageModel.cs

 public class MessageModel
{
public string Title { get; set; }
public string Author { get; set; }
public DocumentType DocType { get; set; } public override string ToString()
{
return Title;
} /// <summary>
/// 验证消息,Title与Author不能为空
/// </summary>
/// <returns></returns>
public bool IsVlid()
{
return !string.IsNullOrWhiteSpace(Title) && !string.IsNullOrWhiteSpace(Author);
}
}

异常代码类MessageException.cs:

 public class MessageException : Exception
{
public MessageException(string message) : base(message)
{
} public MessageException(string message, Exception innerException) : base(message, innerException)
{
}
} public class NoRPCConsumeException : Exception
{
public NoRPCConsumeException(string message) : base(message)
{
} public NoRPCConsumeException(string message, Exception innerException) : base(message, innerException)
{
}
}

①第一个控制台应用程序

namespace PCApp
{
class Program
{
private static IConnection _senderConnection;
private static IModel _channel;
private static int _interval = 1; //消息发送间隔
private static bool isExit; private static void Main(string[] args)
{
Setup(); Console.WriteLine("准备发送消息到extractQueue队列:"); Send(); WaitCommand();
} /// <summary>
/// 初始化
/// </summary>
private static void Setup()
{
var factory = new ConnectionFactory
{
HostName = "localhost",
UserName = "guest",
Password = "guest",
// virtual host只是起到一个命名空间的作用,所以可以多个user共同使用一个virtual host,
//vritual_host= '/',这个是系统默认的,就是说当我们创建一个到rabbitmq的connection时候,它的命名空间是'/',需要注意的是不同的命名空间之间的资源是不能访问的,比如 exchang,queue ,bingding等
//VirtualHost = "test",
AutomaticRecoveryEnabled = true,
TopologyRecoveryEnabled = true
}; try
{
_senderConnection = factory.CreateConnection();
_senderConnection.ConnectionShutdown += _senderConnection_ConnectionShutdown; _channel = _senderConnection.CreateModel();
_channel.QueueDeclare("extractQueue", false, false, false, null);
}
catch (BrokerUnreachableException ex)
{
Console.WriteLine("ERROR: RabbitMQ服务器未启动!");
Thread.Sleep(2000);
isExit = true;
}
} private static void _senderConnection_ConnectionShutdown(object sender, ShutdownEventArgs e)
{
Console.WriteLine("连接已关闭. " + e.ReplyText);
} /// <summary>
/// 等待接收指令
/// </summary>
private static void WaitCommand()
{ while (!isExit)
{
string line = Console.ReadLine().ToLower().Trim();
string[] arr = line.Split(new[] {' '});
string cmd = arr[0];
switch (cmd)
{
case "exit":
Close();
isExit = true;
break;
case "go":
int count = 10;
if (arr.Length > 1)
{
int.TryParse(arr[1], out count);
} Send(count);
break;
case "interval":
int.TryParse(arr[1], out _interval);
break;
case "clear":
Console.Clear();
break;
default:
break;
}
} Console.WriteLine("Goodbye!");
} public static void Send(int msgCount = 10)
{ Console.WriteLine("---------- 开始发送------------"); for (int i = 1; i <= msgCount; i++)
{
string title = "测试文档" + i;
string author = "lexworld" + i;
int docType = i%2 + 1;
string jsonFormat = "{{\"Title\":\"{0}\",\"Author\":\"{1}\",\"DocType\":{2}}}";
string message = string.Format(jsonFormat, title, author, docType);
byte[] body = Encoding.UTF8.GetBytes(message);
try
{
_channel.BasicPublish("", "extractQueue", null, body);
}
catch (AlreadyClosedException ex)
{
Console.WriteLine("ERROR: " + ex.Message);
break;
} Console.WriteLine("Time:" + DateTime.Now + " MSG:" + title); if (_interval > 0)
{
Thread.Sleep(_interval*1000);
}
} Console.WriteLine("---------- 结束 ------------");
} private static string GetMessage()
{
string argLine = string.Join(" ", Environment.GetCommandLineArgs());
string args = argLine.Substring(argLine.IndexOf(" ") + 1);
Console.WriteLine("args:" + args);
string[] arr = args.Split(new[] {','});
string jsonFormat = "{{\"Title\":\"{0}\",\"Author\":\"{1}\",\"DocType\":{2}}}"; return string.Format(jsonFormat, arr[0], arr[1], arr[2]);
} private static void Close()
{
if (_channel != null && _channel.IsOpen)
{
_channel.Close();
} if (_senderConnection != null && _senderConnection.IsOpen)
{
_senderConnection.Close();
}
}
}
}

②第二个控制台应用程序

  class Program
{
private static IConnection _senderConn;
private static IConnection _recvConn;
//private static IModel _senderChannel; 多线程情况下,每个线程需要独立的channel来发送消息
private static IModel _recvChannel;
private static bool isExit; private static void Main(string[] args)
{
Setup(); Console.WriteLine("开始消费extractQueue队列里的消息(同时推送到checkQueue检查队列):"); WaitCommand();
} /// <summary>
/// 初始化
/// </summary>
private static void Setup()
{
var factory = new ConnectionFactory
{
HostName = "localhost",
UserName = "guest",
Password = "guest",
//VirtualHost = "test",
//TopologyRecoveryEnabled = true, //默认为true,如果设置为false,则重连后不会重建相关实体,如:exchange,queue,binding
AutomaticRecoveryEnabled = true //自动重连
}; try
{
_recvConn = factory.CreateConnection();
_recvConn.ConnectionShutdown += ConnectionShutdown;
_recvChannel = _recvConn.CreateModel();
_recvChannel.QueueDeclare("extractQueue", false, false, false, null);
_recvChannel.BasicQos(0, 10, false);
var consumer = new EventingBasicConsumer(_recvChannel);
consumer.Received += consumer_Received;
_recvChannel.BasicConsume("extractQueue", false, consumer); _senderConn = factory.CreateConnection();
IModel channel = _senderConn.CreateModel();
channel.QueueDeclare("checkQueue", false, false, false, null);
//channel.Close();
//这里如果关闭channel的话,自动重连的时候无法恢复checkQueue队列,因为checkQueue是使用channel创建的,恢复的时候还要使用channel,必须保持该信道不关闭
}
catch (BrokerUnreachableException ex)
{
Console.WriteLine("ERROR: RabbitMQ服务器未启动!");
Thread.Sleep(2000);
isExit = true;
}
} private static void ConnectionShutdown(object sender, ShutdownEventArgs e)
{
Console.WriteLine("Connection has already closed.");
} /// <summary>
/// 等待接收指令
/// </summary>
private static void WaitCommand()
{
while (!isExit)
{
string line = Console.ReadLine().ToLower().Trim();
switch (line)
{
case "exit":
Close();
isExit = true;
break;
case "clear":
Console.Clear();
break;
default:
break;
}
} Console.WriteLine("Goodbye!");
} private static void Close()
{
if (_recvChannel != null && _recvChannel.IsOpen)
{
_recvChannel.Close();
} if (_recvConn != null && _recvConn.IsOpen)
{
_recvConn.Close();
} if (_senderConn != null && _senderConn.IsOpen)
{
_senderConn.Close();
}
} #region 异步消息处理,客户端发送完消息后不再等待 /// <summary>
/// 消息接收处理事件,多线程处理消息
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private static void consumer_Received(object sender, BasicDeliverEventArgs e)
{
byte[] body = e.Body;
//bool isSuccess = false; Task.Run(() => HandlingMessage(body, e));
} /// <summary>
/// 消息处理
/// </summary>
/// <param name="msgModel"></param>
/// <param name="e"></param>
private static async void HandlingMessage(byte[] body, BasicDeliverEventArgs e)
{
bool isSuccess = false;
string message = Encoding.UTF8.GetString(body);
IModel _senderChannel = _senderConn.CreateModel(); //多线程中每个线程使用独立的信道 try
{
var msgModel = JsonConvert.DeserializeObject<MessageModel>(message);
if (msgModel == null || !msgModel.IsVlid()) //解析失败或消息格式不正确,拒绝处理
{
throw new MessageException("消息解析失败");
} var random = new Random();
int num = random.Next(0, 4); //模拟处理失败
if (random.Next(0, 11) == 4)
{
throw new Exception("处理失败", null);
} //模拟解析失败
if (random.Next(0, 11) == 8)
{
throw new MessageException("消息解析失败");
} await Task.Delay(num*1000); //这里简单处理,仅格式化输出消息内容
Console.WriteLine("Time:" + DateTime.Now + " ThreadID:" + Thread.CurrentThread.ManagedThreadId + " Used: " + num + "s MSG:" + msgModel); isSuccess = true;
}
catch (MessageException msgEx)
{
Console.WriteLine("Time:" + DateTime.Now + " ThreadID:" + Thread.CurrentThread.ManagedThreadId + " ERROR:" + msgEx.Message + " MSG:" + message);
_recvChannel.BasicReject(e.DeliveryTag, false); //不再重新分发
return;
}
catch (Exception ex)
{
Console.WriteLine("Time:" + DateTime.Now + " ThreadID:" + Thread.CurrentThread.ManagedThreadId + " ERROR:" + ex.Message + " MSG:" + message);
} if (isSuccess)
{
try
{
_senderChannel.BasicPublish("", "checkQueue", null, body); //发送消息到内容检查队列
_recvChannel.BasicAck(e.DeliveryTag, false); //确认处理成功
}
catch (AlreadyClosedException acEx)
{
Console.WriteLine("ERROR:连接已关闭");
}
}
else
{
_recvChannel.BasicReject(e.DeliveryTag, true); //处理失败,重新分发
} _senderChannel.Close();
} #endregion #region 同步消息处理(RPC) #endregion
}

③第三个控制台应用程序

   class Program
{
private static IConnection _recvConn;
private static IConnection _senderConn;
private static IModel _recvChannel;
private static bool isExit; private static void Main(string[] args)
{
Setup(); Console.WriteLine("开始使用checkQueue队列里的消息(同时推送到reportQueue报告队列):"); WaitCommand();
} /// <summary>
/// 初始化
/// </summary>
private static void Setup()
{
var factory = new ConnectionFactory
{
HostName = "localhost",
UserName = "guest",
Password = "guest",
//VirtualHost = "test",
TopologyRecoveryEnabled = true,
AutomaticRecoveryEnabled = true
}; try
{
_recvConn = factory.CreateConnection();
_recvConn.ConnectionShutdown += ConnectionShutdown;
_recvChannel = _recvConn.CreateModel();
_recvChannel.QueueDeclare("checkQueue", false, false, false, null);
_recvChannel.BasicQos(0, 10, false);
var consumer = new EventingBasicConsumer(_recvChannel);
consumer.Received += consumer_Received;
_recvChannel.BasicConsume("checkQueue", false, consumer); _senderConn = factory.CreateConnection();
IModel channel = _senderConn.CreateModel();
channel.QueueDeclare("reportQueue", false, false, false, null);
//channel.Close(); //这里如果关闭channel的话,自动重连的时候无法恢复reportQueue队列,
//因为reportQueue是使用channel创建的,恢复的时候还要使用channel,必须保持该信道不关闭
}
catch (BrokerUnreachableException ex)
{
Console.WriteLine("ERROR: RabbitMQ服务器未启动!");
Thread.Sleep(2000);
isExit = true;
}
} private static void ConnectionShutdown(object sender, ShutdownEventArgs e)
{
Console.WriteLine("连接已关闭.");
} /// <summary>
/// 等待接收指令
/// </summary>
private static void WaitCommand()
{
while (!isExit)
{
string line = Console.ReadLine().ToLower().Trim();
switch (line)
{
case "exit":
Close();
isExit = true;
break;
case "clear":
Console.Clear();
break;
default:
break;
}
} Console.WriteLine("Goodbye!");
} private static void Close()
{
if (_recvChannel != null && _recvChannel.IsOpen)
{
_recvChannel.Close();
} if (_recvConn != null && _recvConn.IsOpen)
{
_recvConn.Close();
} if (_senderConn != null && _senderConn.IsOpen)
{
_senderConn.Close();
}
} #region 异步消息处理,客户端发送完消息后不再等待 /// <summary>
/// 消息接收处理事件,多线程处理消息
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private static void consumer_Received(object sender, BasicDeliverEventArgs e)
{
byte[] body = e.Body; Task.Run(() => HandlingMessage(body, e));
} /// <summary>
/// 消息处理
/// </summary>
/// <param name="msgModel"></param>
/// <param name="e"></param>
private static async void HandlingMessage(byte[] body, BasicDeliverEventArgs e)
{
bool isSuccess = false;
string message = Encoding.UTF8.GetString(body);
IModel _senderChannel = _senderConn.CreateModel(); //多线程中每个线程使用独立的信道 try
{
var msgModel = JsonConvert.DeserializeObject<MessageModel>(message);
if (msgModel == null || !msgModel.IsVlid()) //解析失败或消息格式不正确,拒绝处理
{
throw new MessageException("消息解析失败");
} var random = new Random();
int num = random.Next(0, 4); //模拟处理失败
if (random.Next(0, 11) == 4)
{
throw new Exception("处理失败", null);
} //模拟解析失败
if (random.Next(0, 11) == 8)
{
throw new MessageException("消息解析失败");
} await Task.Delay(num*1000); //这里简单处理,仅格式化输出消息内容
Console.WriteLine("Time:" + DateTime.Now + " ThreadID:" + Thread.CurrentThread.ManagedThreadId +
" Used: " + num + "s MSG:" + msgModel); isSuccess = true;
}
catch (MessageException msgEx)
{
Console.WriteLine("Time:" + DateTime.Now + " ThreadID:" + Thread.CurrentThread.ManagedThreadId + " ERROR:" + msgEx.Message + " MSG:" + message);
_recvChannel.BasicReject(e.DeliveryTag, false); //不再重新分发
return;
}
catch (Exception ex)
{
Console.WriteLine("Time:" + DateTime.Now + " ThreadID:" + Thread.CurrentThread.ManagedThreadId + " ERROR:" + ex.Message + " MSG:" + message);
} if (isSuccess)
{
try
{
_senderChannel.BasicPublish("", "reportQueue", null, body); //发送消息到内容检查队列
_recvChannel.BasicAck(e.DeliveryTag, false); //确认处理成功
}
catch (AlreadyClosedException acEx)
{
Console.WriteLine("ERROR:连接已关闭");
}
}
else
{
_recvChannel.BasicReject(e.DeliveryTag, true); //处理失败,重新分发
} _senderChannel.Close();
} #endregion
}

④第四个控制台应用程序

 class Program
{
private static IConnection _recvConn;
private static IModel _recvChannel;
private static bool isExit;
//private static IConnection _receiverConn; //同步处理(RPC)时使用 private static void Main(string[] args)
{
Setup(); Console.WriteLine("开始消费reportQueue队列里的消息:"); WaitCommand();
} /// <summary>
/// 初始化
/// </summary>
private static void Setup()
{
var factory = new ConnectionFactory
{
HostName = "localhost",
UserName = "test",
Password = "test",
VirtualHost = "test",
TopologyRecoveryEnabled = true,
AutomaticRecoveryEnabled = true
}; try
{
_recvConn = factory.CreateConnection();
_recvConn.ConnectionShutdown += ConnectionShutdown;
_recvChannel = _recvConn.CreateModel();
_recvChannel.QueueDeclare("reportQueue", false, false, false, null);
_recvChannel.BasicQos(0, 10, false);
var consumer = new EventingBasicConsumer(_recvChannel);
consumer.Received += consumer_Received;
_recvChannel.BasicConsume("reportQueue", false, consumer);
}
catch (BrokerUnreachableException ex)
{
Console.WriteLine("ERROR: RabbitMQ服务器未启动!");
Thread.Sleep(2000);
isExit = true;
}
} private static void ConnectionShutdown(object sender, ShutdownEventArgs e)
{
Console.WriteLine("连接已关闭.");
} /// <summary>
/// 等待接收指令
/// </summary>
private static void WaitCommand()
{
while (!isExit)
{
string line = Console.ReadLine().ToLower().Trim();
switch (line)
{
case "exit":
Close();
isExit = true;
break;
case "clear":
Console.Clear();
break;
default:
break;
}
} Console.WriteLine("Goodbye!");
} private static void Close()
{
if (_recvChannel != null && _recvChannel.IsOpen)
{
_recvChannel.Close();
} if (_recvConn != null && _recvConn.IsOpen)
{
_recvConn.Close();
}
} #region 异步消息处理,客户端发送完消息后不再等待 /// <summary>
/// 消息接收处理事件,多线程处理消息
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private static void consumer_Received(object sender, BasicDeliverEventArgs e)
{
byte[] body = e.Body; Task.Run(() => HandlingMessage(body, e));
} /// <summary>
/// 消息处理
/// </summary>
/// <param name="msgModel"></param>
/// <param name="e"></param>
private static async void HandlingMessage(byte[] body, BasicDeliverEventArgs e)
{
bool isSuccess = false;
string message = Encoding.UTF8.GetString(body); try
{
var msgModel = JsonConvert.DeserializeObject<MessageModel>(message);
if (msgModel == null || !msgModel.IsVlid()) //解析失败或消息格式不正确,拒绝处理
{
throw new MessageException("消息解析失败");
} var random = new Random();
int num = random.Next(0, 4); //模拟处理失败
if (random.Next(0, 11) == 4)
{
throw new Exception("处理失败", null);
} //模拟解析失败
if (random.Next(0, 11) == 8)
{
throw new MessageException("消息解析失败");
} await Task.Delay(num*1000); //这里简单处理,仅格式化输出消息内容
Console.WriteLine("Time:" + DateTime.Now + " ThreadID:" + Thread.CurrentThread.ManagedThreadId +
" Used: " + num + "s MSG:" + msgModel); isSuccess = true;
}
catch (MessageException msgEx)
{
Console.WriteLine("Time:" + DateTime.Now + " ThreadID:" + Thread.CurrentThread.ManagedThreadId +
" ERROR:" + msgEx.Message + " MSG:" + message);
_recvChannel.BasicReject(e.DeliveryTag, false); //不再重新分发
return;
}
catch (Exception ex)
{
Console.WriteLine("Time:" + DateTime.Now + " ThreadID:" + Thread.CurrentThread.ManagedThreadId +
" ERROR:" + ex.Message + " MSG:" + message);
} if (isSuccess)
{
try
{
_recvChannel.BasicAck(e.DeliveryTag, false); //确认处理成功
}
catch (AlreadyClosedException acEx)
{
Console.WriteLine("ERROR:连接已关闭");
}
}
else
{
_recvChannel.BasicReject(e.DeliveryTag, true); //处理失败,重新分发
}
} #endregion
}

运行结果如图:

RabbitMQ .NET消息队列使用入门(二)【多个队列间消息传输】的更多相关文章

  1. Rabbit五种消息队列学习(二) – 简单队列

    队列结构图 P:消息的生产者 C:消息的消费者 红色:队列 生产者将消息发送到队列,消费者从队列中获取消息. 测试 1.连接MQ public static Connection getConnect ...

  2. Android 异步消息处理机制前篇(二):深入理解Message消息池

    版权声明:本文出自汪磊的博客,转载请务必注明出处. 上一篇中共同探讨了ThreadLocal,这篇我们一起看下常提到的Message消息池到底是怎么回事,废话少说吧,进入正题. 对于稍有经验的开发人员 ...

  3. RocketMQ入门(3)拉取消息

    转自:http://www.changeself.net/archives/rocketmq入门(3)拉取消息.html RocketMQ入门(3)拉取消息 RocketMQ不止可以直接推送消息,在消 ...

  4. RabbitMQ .NET消息队列使用入门(一)【简单示例】

    首先下载安装包,我都环境是win7 64位: 去官网下载 otp_win64_19.0.exe 和rabbitmq-server-3.6.3.exe安装好 然后开始编程了: (1)创建生产者类: cl ...

  5. RabbitMQ入门教程(十):队列声明queueDeclare

    原文:RabbitMQ入门教程(十):队列声明queueDeclare 版权声明:本文为博主原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明. 本文链接:https:// ...

  6. RabbitMQ 入门系列:7、保障消息不重复消费:产生消息的唯一ID。

    系列目录 RabbitMQ 入门系列:1.MQ的应用场景的选择与RabbitMQ安装. RabbitMQ 入门系列:2.基础含义:链接.通道.队列.交换机. RabbitMQ 入门系列:3.基础含义: ...

  7. RabbitMQ入门教程(十):队列声明queueDeclare(转载)

    原文转载至:https://blog.csdn.net/vbirdbest/article/details/78670550 简介本节主要讨论队列声明的各个参数 queueDeclare(String ...

  8. RabbitMQ 入门系列:6、保障消息:不丢失:发送方、Rabbit存储端、接收方。

    系列目录 RabbitMQ 入门系列:1.MQ的应用场景的选择与RabbitMQ安装. RabbitMQ 入门系列:2.基础含义:链接.通道.队列.交换机. RabbitMQ 入门系列:3.基础含义: ...

  9. 分布式消息系统Jafka入门指南之二

    分布式消息系统Jafka入门指南之二 作者:chszs,转载需注明.博客主页:http://blog.csdn.net/chszs 三.Jafka的文件夹结构 1.安装tree命令 $ sudo yu ...

随机推荐

  1. 【转】IDEA 中tomcat图片储存和访问虚拟路径

    1.idea 修改Tomcat的虚拟路径(第一种方法)修改配置文件有很多种,但是一直不成功;后来想还是idea的配置原因,这里tomcat虚拟路径只说一种; 修改Tomcat安装路径下server.x ...

  2. jquery制作动态添加表单行与删除表单行

    <script type="text/javascript" src="js/jquery1.7.js"></script> <s ...

  3. Python那点事

    目录 Python那点事 一. Python介绍 二. 目前python的主要领域 三.Python的运用 四. Python的发展史 Python的种类 Python那点事 相信很多小伙伴会跳过此环 ...

  4. 【模板】Link-Cut Tree

    #include<cstdio> #include<algorithm> #define N 500010 #define rg register #define ls (c[ ...

  5. CODEVS1281 Xn数列 (矩阵乘法+快速乘)

    真是道坑题,数据范围如此大. 首先构造矩阵 [ f[0] , 1] * [ a,0 ] ^n= [ f[n],1 ] [ c,1 ] 注意到m, a, c, x0, n, g<=10^18,所以 ...

  6. springCloud学习-分布式配置中心(Spring Cloud Config)

    1.简介 Spring Cloud Config :分布式配置中心,方便服务配置文件统一管理,它支持配置服务放在配置服务的内存中(即本地),也支持放在远程Git仓库中.在spring cloud co ...

  7. SSM(spring mvc+spring+mybatis)学习路径——1-2、spring事务管理

    目录 1-2 Spring事务管理 概念介绍 事务回顾 事务的API介绍 Spring 事务管理 转账案例 编程式事务管理 声明式事务管理 使用XML配置声明式事务 基于tx/aop 使用注解配置声明 ...

  8. N天学习一个linux命令之rsync

    用途 主要用于本地和远程主机同步文件 特性 1 使用增量传输算法(delta-transfer algorithm) 2 支持ssh,rsync协议 3 可以用于本地同步文件 4 本地和远程主机都需要 ...

  9. AutoCAD 2014:安装时发生allied product not found错误

    有个朋友在安装AutoCAD 2014时不慎误删了一个文件夹,结果导致安装AutoCAD时总是跳出”allied product not found”的错误. Google搜了下,解决方案如下: 1. ...

  10. Linux vim 入门 配置 及 使用初步

    网上能够找到的,关于VI的教程,更是多为能吓死人的上百页说明.事实上, 从我个人的实践看,全然不须要如此夸张.要完毕最主要的编辑.仅仅要熟悉几个命令,就是把VIM用得非常好. 这里就列举一下: Esc ...