一、MSMQ简介
MSMQ(微软消息队列)是Windows操作系统中消息应用程序的基础,是用于创建分布式、松散连接的消息通讯应用程序的开发工具。消息队列
和电子邮件有着很多相似处,他们都包含多个属性,用于保存消息,消息类型中都指出发送者和接收者的地址;然而他们的用处却有着很大的
区别:消息队列的发送者和接收者是应用程序,而电子邮件的发送者和接收者通常是人。如同电子邮件一样,消息队列的发送和接收也不需要
发送者和接收者同时在场,可以存储在消息队列或是邮件服务器中。
二、消息队列的安装
默认情况下安装操作系统是不安装消息队列的,你可以在控制面板中找到添加/删除程序,然后选择添加/删除Windows组件一项,然后选择应
用程序服务器,双击它进入详细资料中选择消息队列一项进行安装,如图:



三、消息队列类型
消息对列分为3类:
公共队列
MachineName\QueueName
能被别的机器所访问,如果你的多个项目中用到消息队列,那么你可以把队列定义为公共队列
专用队列
MachineName\Private$\QueueName
只针对于本机的程序才可以调用的队列,有些情况下为了安全起见定义为私有队列。
日志队列
MachineName\QueueName\Journal$
四、消息队列的创建
MessageQueue Mq=new MessageQueue(“.\\private$\\Mymq”);
通过Path属性引用消息队列的代码也十分简单:
MessageQueue Mq=new MessageQueue();
Mq.Path=”.\\private$\\Mymq”;
使用 Create 方法可以在计算机上创建队列:
System.Messaging.MessageQueue.Create(@".\private$\Mymq");
这里注意由于在C#中要记住用反斜杠将“\”转义。
由于消息对列所放置的地方经常改变,所以建议消息队列路径不要写死,建议放在配置文件中。
五、消息的发送
消息的发送可以分为简单消息和复杂消息,简单消息类型就是常用的数据类型,例如整型、字符串等数据;复杂消息的数据类型通常对应于系
统中的复杂数据类型,例如结构,对象等等。
Mq.Send("Hello!");
在这里建议你可以事先定义一个对象类,然后发送这个对象类的实例对象,这样以后无论在增加什么发送信息,只需在对象类中增加
相应的属性即可。
六、消息的接收和阅读
(1)同步接收消息
接收消息的代码很简单:
Mq.Receive();
Mq.Receive(TimeSpan timeout); //设定超时时间
Mq.ReceiveById(ID);
Mq.Peek();
通过Receive方法接收消息同时永久性地从队列中删除消息;
通过Peek方法从队列中取出消息而不从队列中移除该消息。
如果知道消息的标识符(ID),还可以通过ReceiveById方法和PeekById方法完成相应的操作。
(2)异步接受消息
利用委托机制:
MessQueue.ReceiveCompleted +=new ReceiveCompletedEventHandler(mq_ReceiveCompleted);
(3)消息阅读
在应用程序能够阅读的消息和消息队列中的消息格式不同,应用程序发送出去的消息经过序列化以后才发送给了消息队列
而在接受端必须反序列化,利用下面的代码可以实现:
public void mq_ReceiveCompleted(object sender, System.Messaging.ReceiveCompletedEventArgs e)
{
System.Messaging.Message m = MessQueue.EndReceive(e.AsyncResult);
m.Formatter = new System.Messaging.XmlMessageFormatter(new string[]{"System.String,mscorlib"});
Console.WriteLine("Message: " + (string)m.Body);
MessQueue.BeginReceive() ;
}
反序列化还有另一种写法:
m.Formatter = new XmlMessageFormatter ( new Type [] { typeof (string) } );
七、由于消息队列的代码有些是固定不便的,所以把这些代码封装成一个类方便以后使用:
1
using System;
2
using System.Messaging;
3
using System.Threading;
5
6
namespace LoveStatusService
7

{
8
/**//// <summary>
9
/// Summary description for Msmq.
10
/// </summary>
11
public class Msmq
12
{
13
public Msmq()
14
{
15
//
16
// TODO: Add constructor logic here
17
//
18
}
19
20
21
private MessageQueue _messageQueue=null;
22
//最大并发线程数
23
private static int MAX_WORKER_THREADS=Convert.ToInt32( System.Configuration.ConfigurationSettings.AppSettings["MAX_WORKER_THREADS"].ToString());
24
//Msmq路径
25
private static string MsmqPath=System.Configuration.ConfigurationSettings.AppSettings["LoveStatusMQPath"];
26
//等待句柄
27
private WaitHandle[] waitHandleArray = new WaitHandle[MAX_WORKER_THREADS];
28
//任务类型
29
//1. Send Email 2. Send Message 3. Send Email and Message
30
private string TaskType=System.Configuration.ConfigurationSettings.AppSettings["TaskType"];
31
public MessageQueue MessQueue
32
{
33
get
34
{
35
36
if (_messageQueue==null)
37
{
38
if(MessageQueue.Exists(MsmqPath))
39
{
40
_messageQueue = new MessageQueue(MsmqPath);
41
}
42
else
43
{
44
_messageQueue = MessageQueue.Create(MsmqPath);
45
}
46
}
47
48
49
return _messageQueue;
50
}
51
}
52
53
54
Private Method#region Private Method
55
56
private void mq_ReceiveCompleted(object sender, System.Messaging.ReceiveCompletedEventArgs e)
57
{
58
MessageQueue mqq = (MessageQueue)sender;
59
System.Messaging.Message m = mqq.EndReceive(e.AsyncResult);
60
//m.Formatter = new System.Messaging.XmlMessageFormatter(new string[]{"System.String,mscorlib"});
61
m.Formatter =new System.Messaging.XmlMessageFormatter(new Type[]
{typeof(UserObject)}) ;
62
//log.Info("Receive UserID: " + (string)m.Body) ;
63
UserObject obj=(UserObject)m.Body ;
64
long curUserId=obj.curUserID ;
65
long oppUserId=obj.oppUserID;
66
string curUserName=obj.curUserName;
67
string oppUserName=obj.oppUserName;
68
string curEmail=obj.curEmail ;
69
string oppEmail=obj.oppEmail;
70
string subject =obj.subject ;
71
string body=obj.body ;
72
//AppLog.log.Info("curUserId:"+curUserId) ;
73
//AppLog.log.Info("oppUserId:"+oppUserId) ;
74
AppLog.log.Info("==type="+TaskType) ;
75
switch(TaskType)
76
{
77
//Email
78
case "1":
79
EmailForMQ.SendEmailForLoveStatus(curEmail,oppEmail,curUserName,oppUserName,subject) ;
80
AppLog.log.Info("==Send to=="+oppEmail) ;
81
break;
82
//Message
83
case "2":
84
MessageForMQ.SendMessage(curUserId,oppUserId,subject,body) ;
85
AppLog.log.Info("==Send Msg to=="+oppUserId) ;
86
break;
87
//Email and Message
88
case "3":
89
EmailForMQ.SendEmailForLoveStatus(curEmail,oppEmail,curUserName,oppUserName,subject) ;
90
AppLog.log.Info("==Send to=="+oppEmail) ;
91
MessageForMQ.SendMessage(curUserId,oppUserId,subject,body) ;
92
AppLog.log.Info("==Send Msg to=="+oppUserId) ;
93
break;
94
default:
95
break;
96
97
}
98
mqq.BeginReceive() ;
99
100
}
101
102
#endregion
103
104
Public Method#region Public Method
105
106
//一个将对象发送到队列的方法,这里发送的是对象
107
public void SendUserIDToMQ(object arr)
108
{
109
MessQueue.Send(arr) ;
110
Console.WriteLine("Ok") ;
111
Console.Read() ;
112
}
113
114
//同步接受队列内容的方法
115
public void ReceiveFromMQ()
116
{
117
Message ms=new Message() ;
118
119
//ms=MessQueue.Peek();
120
try
121
{
122
ms=MessQueue.Receive(new TimeSpan(0,0,5));
123
if(ms!=null)
124
{
125
ms.Formatter = new XmlMessageFormatter ( new Type []
{ typeof (string) } );
126
AppLog.log.Info((string)ms.Body) ;
127
}
128
}
129
catch(Exception ex)
130
{
131
132
}
133
134
135
}
136
137
//开始监听工作线程
138
public void startListen()
139
{
140
AppLog.log.Info("--Thread--"+MAX_WORKER_THREADS) ;
141
MessQueue.ReceiveCompleted +=new ReceiveCompletedEventHandler(mq_ReceiveCompleted);
142
143
//异步方式,并发
144
145
for(int i=0; i<MAX_WORKER_THREADS; i++)
146
{
147
// Begin asynchronous operations.
148
waitHandleArray[i] = MessQueue.BeginReceive().AsyncWaitHandle;
149
}
150
151
AppLog.log.Info("------Start Listen--------") ;
152
153
return;
154
155
}
156
157
158
//停止监听工作线程
159
public void stopListen()
160
{
161
162
for(int i=0;i<waitHandleArray.Length;i++)
163
{
164
165
try
166
{
167
waitHandleArray[i].Close();
168
}
169
catch
170
{
171
AppLog.log.Info("---waitHandleArray[i].Close() Error!-----") ;
172
}
173
174
}
175
176
try
177
{
178
// Specify to wait for all operations to return.
179
WaitHandle.WaitAll(waitHandleArray,1000,false);
180
}
181
catch
182
{
183
AppLog.log.Info("---WaitHandle.WaitAll Error!-----") ;
184
}
185
AppLog.log.Info("------Stop Listen--------") ;
186
187
}
188
189
#endregion
190
191
192
193
194
}
195
}
196
UserObject的代码
1
using System;
2
3
namespace Goody9807
4

{
5
/**//// <summary>
6
/// 用与在MQ上传输数据的对象
7
/// </summary>
8
public class UserObject
9
{
10
public UserObject()
11
{
12
//
13
// TODO: Add constructor logic here
14
//
15
}
16
17
private long _curUserID;
18
public long curUserID
19
{
20
get
21
{
22
return _curUserID;
23
}
24
set
25
{
26
_curUserID=value;
27
}
28
}
29
30
private string _curUserName="";
31
public string curUserName
32
{
33
get
34
{
35
return _curUserName;
36
}
37
set
38
{
39
_curUserName=value;
40
}
41
}
42
43
private string _curEmail="";
44
public string curEmail
45
{
46
get
47
{
48
return _curEmail;
49
}
50
set
51
{
52
_curEmail=value;
53
}
54
}
55
56
57
private long _oppUserID;
58
public long oppUserID
59
{
60
get
61
{
62
return _oppUserID;
63
}
64
set
65
{
66
_oppUserID=value;
67
}
68
}
69
70
private string _oppUserName="";
71
public string oppUserName
72
{
73
get
74
{
75
return _oppUserName;
76
}
77
set
78
{
79
_oppUserName=value;
80
}
81
}
82
83
private string _oppEmail="";
84
public string oppEmail
85
{
86
get
87
{
88
return _oppEmail;
89
}
90
set
91
{
92
_oppEmail=value;
93
}
94
}
95
96
private string _subject ="";
97
public string subject
98
{
99
get
100
{
101
return _subject;
102
}
103
set
104
{
105
_subject=value;
106
}
107
}
108
109
private string _body="";
110
public string body
111
{
112
get
113
{
114
return _body;
115
}
116
set
117
{
118
_body=value;
119
}
120
}
121
}
122
}
123
另一个同事写的封装类


1
using System;
2
3
using System.Threading;
4
5
using System.Messaging;
6
7
8
9
namespace Wapdm.SmsApp
10
11

{
12
13
/**//// <summary>
14
15
/// <para>
16
17
/// A Logger implementation that writes messages to a message queue.
18
19
/// The default event formatter used is an instance of XMLEventFormatter
20
21
/// </para>
22
23
/// </summary>
24
25
public sealed class MsgQueue
26
27
{
28
29
30
31
private const string BLANK_STRING = "";
32
33
private const string PERIOD = @".\private$"; //".";
34
35
private const string ELLIPSIS = "
";
36
37
38
39
private string serverAddress;
40
41
private string queueName;
42
43
private string queuePath;
44
45
46
47
private bool IsContextEnabled;
48
49
50
51
private MessageQueue queue;
52
53
54
55
private object queueMonitor = new object();
56
57
58
59
private MsgQueue()
{}
60
61
62
63
public static MsgQueue mq = null;
64
65
public static WaitHandle[] waitHandleArray = new WaitHandle[Util.MAX_WORKER_THREADS];
66
67
68
69
public MsgQueue(string _serverAddress, string _queueName, string _summaryPattern)
70
71
{
72
73
if ((_serverAddress == null) || (_queueName == null) || (_summaryPattern == null))
74
75
{
76
77
throw new ArgumentNullException();
78
79
}
80
81
ServerAddress = _serverAddress;
82
83
QueueName = _queueName;
84
85
IsContextEnabled = true;
86
87
}
88
89
90
91
public MsgQueue(string _serverAddress, string _queueName)
92
93
{
94
95
if ((_serverAddress == null) || (_queueName == null))
96
97
{
98
99
throw new ArgumentNullException();
100
101
}
102
103
ServerAddress = _serverAddress;
104
105
QueueName = _queueName;
106
107
IsContextEnabled = true;
108
109
}
110
111
112
113
public MsgQueue(string _queueName)
114
115
{
116
117
if (_queueName == null)
118
119
{
120
121
throw new ArgumentNullException();
122
123
}
124
125
serverAddress = PERIOD;
126
127
QueueName = _queueName;
128
129
IsContextEnabled = true;
130
131
if ( IsContextEnabled == false )
132
133
throw new ArgumentNullException();
134
135
}
136
137
138
139
public string ServerAddress
140
141
{
142
143
get
144
145
{
146
147
return serverAddress;
148
149
}
150
151
set
152
153
{
154
155
if (value == null)
156
157
{
158
159
value = PERIOD;
160
161
}
162
163
value = value.Trim();
164
165
if (value.Equals(BLANK_STRING))
166
167
{
168
169
throw new ArgumentException("Invalid value (must contain non-whitespace characters)");
170
171
}
172
173
lock (queueMonitor)
174
175
{
176
177
serverAddress = value;
178
179
queuePath = serverAddress + '\\' + queueName;
180
181
InitializeQueue();
182
183
}
184
185
}
186
187
}
188
189
190
191
public string QueueName
192
193
{
194
195
get
196
197
{
198
199
return queueName;
200
201
}
202
203
set
204
205
{
206
207
if (value == null)
208
209
{
210
211
throw new ArgumentNullException();
212
213
}
214
215
value = value.Trim();
216
217
if (value.Equals(BLANK_STRING))
218
219
{
220
221
throw new ArgumentException("Invalid value (must contain non-whitespace characters)");
222
223
}
224
225
lock (queueMonitor)
226
227
{
228
229
queueName = value;
230
231
queuePath = serverAddress + '\\' + queueName;
232
233
InitializeQueue();
234
235
}
236
237
}
238
239
}
240
241
242
243
private void InitializeQueue()
244
245
{
246
247
lock (queueMonitor)
248
249
{
250
251
if (queue != null)
252
253
{
254
255
try
{ queue.Close(); }
256
257
catch
{}
258
259
queue = null;
260
261
}
262
263
264
265
try
266
267
{
268
269
if(!MessageQueue.Exists(queuePath))
270
271
MessageQueue.Create(queuePath);
272
273
}
274
275
catch
{}
276
277
try
278
279
{
280
281
queue = new MessageQueue(queuePath);
282
283
queue.SetPermissions("EveryOne",MessageQueueAccessRights.FullControl);
284
285
queue.Formatter = new XmlMessageFormatter(new Type[]
{typeof(MoMsg)});
286
287
}
288
289
catch (Exception e)
290
291
{
292
293
try
{ queue.Close(); }
294
295
catch
{}
296
297
queue = null;
298
299
throw new ApplicationException("Couldn't open queue at '" + queuePath + "': " + e.GetType().FullName + ": " + e.Message);
300
301
}
302
303
304
305
}
306
307
}
308
309
310
311
private void AcquireResources()
312
313
{
314
315
InitializeQueue();
316
317
}
318
319
320
321
public void ReleaseResources()
322
323
{
324
325
lock (queueMonitor)
326
327
{
328
329
if (queue != null)
330
331
{
332
333
try
334
335
{
336
337
queue.Close();
338
339
}
340
341
catch
{}
342
343
queue = null;
344
345
}
346
347
}
348
349
}
350
351
352
353
//阻塞方式
354
355
public MoMsg Read( )
356
357
{
358
359
MoMsg _event = null;
360
361
lock (queueMonitor)
362
363
{
364
365
if (queue == null)
366
367
{
368
369
InitializeQueue();
370
371
}
372
373
try
374
375
{
376
377
Message message = queue.Receive( new TimeSpan(0,0,1) );//等待10秒
378
379
_event = (MoMsg) (message.Body);
380
381
return _event;
382
383
}
384
385
catch (Exception )
386
387
{
388
389
try
{ queue.Close(); }
390
391
catch
{}
392
393
queue = null;
394
395
}
396
397
}
398
399
return null;
400
401
}
402
403
404
405
public void Write(MoMsg _event)
406
407
{
408
409
if (_event == null)
410
411
{
412
413
return;
414
415
}
416
417
lock (queueMonitor)
418
419
{
420
421
try
422
423
{
424
425
if (queue == null)
426
427
{
428
429
InitializeQueue();
430
431
}
432
433
434
435
Message message = new Message();
436
437
message.Priority = _event.Priority;
438
439
message.Recoverable = true;
440
441
message.Body = _event; //eventFormatter.Format(_event);
442
443
444
445
queue.Send(message);
446
447
}
448
449
catch (Exception e)
450
451
{
452
453
try
{ queue.Close(); }
454
455
catch
{}
456
457
queue = null;
458
459
Util.Log.log("Couldn't write Message (" + e.GetType().FullName + ": " + e.Message + ")");
460
461
}
462
463
}
464
465
}
466
467
468
469
public static bool statusTest()
470
471
{
472
473
bool reValue = false;
474
475
try
476
477
{
478
479
MessageEnumerator re = mq.queue.GetMessageEnumerator();
480
481
bool rev = re.MoveNext();
482
483
reValue = true;
484
485
}
486
487
catch
488
489
{
490
491
reValue = false;
492
493
}
494
495
496
497
return reValue;
498
499
}
500
501
502
503
public static void startListen()
504
505
{
506
507
mq = new MsgQueue(Util.MqName);
508
509
510
511
mq.queue.ReceiveCompleted +=new ReceiveCompletedEventHandler(queue_ReceiveCompleted);
512
513
514
515
//异步方式,并发
516
517
for(int i=0; i<Util.MAX_WORKER_THREADS; i++)
518
519
{
520
521
// Begin asynchronous operations.
522
523
waitHandleArray[i] =
524
525
mq.queue.BeginReceive().AsyncWaitHandle;
526
527
}
528
529
530
531
return;
532
533
}
534
535
536
537
public static void stopListen()
538
539
{
540
541
542
543
for(int i=0;i<waitHandleArray.Length;i++)
544
545
{
546
547
try
548
549
{
550
551
waitHandleArray[i].Close();
552
553
}
554
555
catch
556
557
{
558
559
//忽略错误
560
561
}
562
563
}
564
565
566
567
try
568
569
{
570
571
// Specify to wait for all operations to return.
572
573
WaitHandle.WaitAll(waitHandleArray,1000,false);
574
575
}
576
577
catch
578
579
{
580
581
//忽略错误
582
583
}
584
585
}
586
587
588
589
private static void queue_ReceiveCompleted(object sender, ReceiveCompletedEventArgs e)
590
591
{
592
593
// Connect to the queue.
594
595
MessageQueue mqq = (MessageQueue)sender;
596
597
598
599
// End the asynchronous Receive operation.
600
601
Message m = mqq.EndReceive(e.AsyncResult);
602
603
604
605
Util.ProcessMo((MoMsg)(m.Body));
606
607
608
609
if(Util.isRunning)
610
611
{
612
613
// Restart the asynchronous Receive operation.
614
615
mqq.BeginReceive();
616
617
}
618
619
620
621
return;
622
623
}
624
625
}
626
627
}
628
629
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· Ollama——大语言模型本地部署的极速利器
· [AI/GPT/综述] AI Agent的设计模式综述