代码:

  1. namespace RabbitMQDemo
  2. {
  3. public partial class WorkQueues : Form
  4. {
  5. private string queueName = "WorkQueues_queue";
  6. Action<string, TextBox> SetText;
  7. private readonly static WorkQueues _WorkQueues;
  8. static WorkQueues()
  9. {
  10. _WorkQueues = new WorkQueues();
  11. }
  12. /// <summary>
  13. /// 单例模式
  14. /// </summary>
  15. public static WorkQueues SingleForm { get { return _WorkQueues; } }
  16. private WorkQueues()
  17. {
  18. CheckForIllegalCrossThreadCalls = false;
  19. InitializeComponent();
  20. ReceiveMsg(txtConsumer1);//消费者1
  21. ReceiveMsg(txtConsumer2);//消费者2
  22. SetText += OnSetText;
  23. }
  24.  
  25. private void btnSendMsg_Click(object sender, EventArgs e)
  26. {
  27. SendMsg();
  28. }
  29. /// <summary>
  30. /// 发送消息
  31. /// </summary>
  32. private void SendMsg()
  33. {
  34. string message = txtPublisher.Text;
  35. if (message.Trim().Length <= )
  36. {
  37. MessageBox.Show("请输入要发送的消息");
  38. }
  39. var factory = new ConnectionFactory() { HostName = "localhost" };
  40. using (var connection = factory.CreateConnection())
  41. using (var channel = connection.CreateModel())
  42. {
  43. //durable-队列持久化,为true的时候告诉rabbitmq不管服务器停止运行还是崩溃或重启都不能丢失队列queue(已经声明过的队列无法再重新定义durable的值,如果这样做了,服务器会返回一个错误)
  44. channel.QueueDeclare(queue: queueName,
  45. durable: true,
  46. exclusive: false,
  47. autoDelete: false,
  48. arguments: null);
  49.  
  50. var body = Encoding.UTF8.GetBytes(message);
  51.  
  52. //消息持久化-为true的时候告诉rabbitmq不管服务器停止运行还是崩溃或重启都不能丢失队列queue,这种消息持久化方式不能保证消息永不丢失,它告诉rabbitmq将消息保存到磁盘,但是当rabbitmq接收到消息但是还没有保存的时候有一个很短的时间窗口.此外,rabbitmq不会为每个消息执行fsync(2)-它可能只是保存到缓存中,而不是真正的写入磁盘.这种消息持久化方式保证不强,用于要求不那么严格的任务队列,已经足够,如果要更完善的消息持久化,可以使用publisher confirms
  53. var properties = channel.CreateBasicProperties();
  54. properties.Persistent = true;
  55.  
  56. channel.BasicPublish(exchange: "",
  57. routingKey: queueName,
  58. basicProperties: properties,
  59. body: body);
  60. }
  61. }
  62. /// <summary>
  63. /// 接收消息
  64. /// </summary>
  65. private void ReceiveMsg(TextBox box)
  66. {
  67. try
  68. {
  69. var factory = new ConnectionFactory() { HostName = "localhost" };
  70. var connection = factory.CreateConnection();
  71. var channel = connection.CreateModel();
  72.  
  73. channel.QueueDeclare(
  74. queue: queueName,
  75. durable: true,
  76. exclusive: false,
  77. autoDelete: false,
  78. arguments: null);
  79.  
  80. //公平分发
  81. //默认情况下rabbitmq会将消息平均地发给消费者,不管消费者是否正在处理消息,也不会考虑消费者是否返回未确认消息,这会造成资源浪费.假如队列中有10条消息,有2个消费者,那么每个消费者会收到5条消息,如果说其中5条消息是要花费大量时间的,并且这5条消息都刚好发送给了第一个消费者,那么第1个消费者将会一直处于忙碌状态,而第二个消费者假如处理的另外5条消息都不花费多少时间那么第二个消费者就会闲置.prefetchCount=1告诉rabbitmq不要向我发送新的消息,直到我处理并确认了前一个消息,然后rabbitmq将会把消息发给下一个消费者
  82. //假如所有的消费者都处于忙碌状态(没有反馈消息确认给rabbitmq)那么消息将在队列中排队等待,这可能造成queue存储空间不足,需要采取预防措施
  83. channel.BasicQos(
  84. prefetchSize: ,
  85. prefetchCount: ,
  86. global: false);
  87.  
  88. var consumer = new EventingBasicConsumer(channel);
  89. consumer.Received += (model, ea) =>
  90. {
  91. var msg = Encoding.UTF8.GetString(ea.Body);
  92.  
  93. //要求发送的消息包含'.',每个'.'让线程花1秒时间处理,10个花10秒
  94. int dots = msg.Split('.').Length - ;
  95. Thread.Sleep(dots * );
  96.  
  97. //将消息显示在界面上
  98. box.Invoke(SetText, msg, box);
  99.  
  100. //手动想rabbitmq发送消息确认
  101. channel.BasicAck(
  102. deliveryTag: ea.DeliveryTag,
  103. multiple: false);
  104. };
  105.  
  106. //消息确认
  107. //noAck-自动回复消息 为true的时候consumer收到了一个消息就会立刻返回一个标记给rabbitmq告诉它这个消息我已经拿到了,你可以自由的删除掉它,至于consumer怎么处理这个消息或者处理的过程中出错了在rabbitmq中将找不回这个消息(使用这种方式要确保consumer不会挂掉,否则消息容易丢失)
  108. channel.BasicConsume(
  109. queue: queueName,
  110. noAck: false,
  111. consumer: consumer);
  112. }
  113. catch (Exception ex)
  114. {
  115. MessageBox.Show(ex.ToString());
  116. }
  117. }
  118.  
  119. private void OnSetText(string text, TextBox box)
  120. {
  121. box.Text += string.Format("{0}\r\n", text);
  122. }
  123. }
  124. }

界面:

大概流程:

生产者发送一条消息,如果消息包含英文句点'.',那么每一个句点标识消费者处理这条消息要花费的时间,这个时候该消费者就不再接收来自rabbitmq的消息,rabbitmq将会把消息发给下一个消费者以保证不会有消费者要么一直忙碌要么一直闲置的bug,同时要注意的是,一旦一个消息发送给了一个消费者另一个消费者就得不到这条消息,只能拿到下一条

测试结果:

WinForm实现Rabbitmq官网6个案例-Work Queues的更多相关文章

  1. WinForm实现Rabbitmq官网6个案例-RPC

    获取源码 客户端代码: namespace RabbitMQDemo { public partial class RPC : Form { private readonly static RPC _ ...

  2. WinForm实现Rabbitmq官网6个案例-Publishe/Subscribe

    代码: namespace RabbitMQDemo { public partial class PublishSubscribe : Form { private string exchangeN ...

  3. WinForm实现Rabbitmq官网6个案例-Hello World

    先上代码 namespace RabbitMQDemo { public partial class HelloWorld : Form { string queueName1 = "hel ...

  4. WinForm实现Rabbitmq官网6个案例-Topics

    代码: namespace RabbitMQDemo { public partial class Topics : Form { private string exchangeName = &quo ...

  5. WinForm实现Rabbitmq官网6个案例-Routing

    代码: namespace RabbitMQDemo { public partial class Routing : Form { private string exchangeName = &qu ...

  6. 官网英文版学习——RabbitMQ学习笔记(一)认识RabbitMQ

    鉴于目前中文的RabbitMQ教程很缺,本博主虽然买了一本rabbitMQ的书,遗憾的是该书的代码用的不是java语言,看起来也有些不爽,且网友们不同人学习所写不同,本博主看的有些地方不太理想,为此本 ...

  7. 2022年官网下安装RabbitMQ最全版与官网查阅方法

    目录 一.Erlang环境部署 1.百度搜索"Erlang",或者访问网址:https://www.erlang.org/,找到DOWNLOAD双击进入. 2.找到支持的windo ...

  8. Yeoman 官网教学案例:使用 Yeoman 构建 WebApp

    STEP 1:设置开发环境 与yeoman的所有交互都是通过命令行.Mac系统使用terminal.app,Linux系统使用shell,windows系统可以使用cmder/PowerShell/c ...

  9. MXNet官网案例分析--Train MLP on MNIST

    本文是MXNet的官网案例: Train MLP on MNIST. MXNet所有的模块如下图所示: 第一步: 准备数据 从下面程序可以看出,MXNet里面的数据是一个4维NDArray. impo ...

随机推荐

  1. IDEA External libraries 不显示Maven中引入的repository

    原文:https://blog.csdn.net/dj_dengjian/article/details/88668012 记录一下遇到的这个问题的解决方法,也是困惑了半天,感觉这是maven的bug ...

  2. Hadoop2.5.0伪分布式环境搭建

    本章主要介绍下在Linux系统下的Hadoop2.5.0伪分布式环境搭建步骤.首先要搭建Hadoop伪分布式环境,需要完成一些前置依赖工作,包括创建用户.安装JDK.关闭防火墙等. 一.创建hadoo ...

  3. Mac下JDK卸载方法

    注:要卸载 Java,必须具有管理员权限,并且必须以 root 用户身份或者使用 sudo 工具来执行删除命令. 按照下面所示,删除一个目录和一个文件(符号链接): 1.单击位于停靠栏中的 Finde ...

  4. Linus' Law

    Given enough eyeballs, all bugs are shallow.                                               ------埃里克 ...

  5. spring boot快速入门 2 :属性配置

    属性配置:在application.properties中配置 第一步:配置端口号和项目名 并启动 第二步:在浏览器查看请求 第二种配置方式: 在application.yml中配置.(较为常用) 注 ...

  6. 由UI刷新谈到线程安全和Android单线程模型

    1.为什么说invalidate()不能直接在线程中调用? Android提供了Invalidate方法实现界面刷新,但是Invalidate不能直接在非UI主线程中调用,因为他是违背了单线程模型:A ...

  7. reifiable type与raw type

    下面的逻辑需要明白如下两个概念: 4.7. Reifiable Types 4.8. Raw Types 举几个是Reifiable Types的例子,如下: class A{} class B< ...

  8. Capture Conversion解读

    Let G name a generic type declaration with n type parameters A1,...,An with corresponding bounds U1, ...

  9. Java Struts(文件下载)

    1.从注册成功页面跳转至用户详情页面(跳转至UserListAction) 2.UserListAction调用service获得用户列表,并将这些数据传送到UserList.jsp中,UserLis ...

  10. [心平气和读经典]The TCP/IP Guide(002)

    The TCP/IP Guide [Page 41, 42] Goals of The TCP/IP Guide | 本书的目标 Every author who sets out to write ...