文章的目的为了记录使用C# 开发学习的经历。开发流程和要点有些记忆模糊,赶紧记录,防止忘记。
相关链接:
开源 C# 快速开发(十六)数据库--sqlserver增删改查
推荐链接:
开源 C# .net mvc 开发(一)WEB搭建_c#部署web程序-CSDN博客
开源 C# .net mvc 开发(二)网站快速搭建_c#网站开发-CSDN博客
开源 C# .net mvc 开发(三)WEB内外网访问-CSDN博客
开源 C# .net mvc 开发(四)工程结构、页面提交以及显示-CSDN博客
开源 C# .net mvc 开发(五)常用代码快速开发_c# mvc开发-CSDN博客
开源 C# .net mvc 开发(六)发送邮件、定时以及CMD编程-CSDN博客
开源 C# .net mvc 开发(七)动态图片、动态表格和json数据生成-CSDN博客
开源 C# .net mvc 开发(八)IIS Express轻量化Web服务器的配置和使用-CSDN博客
开源 C# .net mvc 开发(九)websocket--服务器与客户端的实时通信-CSDN博客
本章节主要内容是:进程间 Windows消息队列通信,基于MSMQ 。
核心概念
-
消息队列
-
就像一个"邮箱"。发送方进程将消息发送到这个队列,接收方进程从同一个队列中读取消息。
-
队列由消息队列服务器管理,消息被持久化存储(通常在磁盘上),确保了可靠性。
-
-
异步通信
-
发送方和接收方不需要同时在线。
-
发送方发送完消息后就可以继续自己的工作,无需等待接收方立即处理。
-
接收方可以在自己方便的时候再去队列中获取并处理消息。这实现了进程间的 "解耦"。
-
-
可靠传递
- 因为消息被存储在持久化介质中(如硬盘),即使发送后接收方程序崩溃、网络中断或计算机关机,消息也不会丢失。当接收方程序重新启动后,它仍然可以从队列中收到那条消息。
MSMQ 的工作模式
-
点对点模式:一个发送方将消息发送到一个特定的队列,一个(且只有一个)接收方从该队列中取出消息进行处理。
-
多播模式:一个发送方发送一条消息,可以被多个订阅了该消息的接收方同时接收。
主要特点和优势
-
解耦:发送和接收进程相互独立,不需要知道对方的存在、状态或位置。
-
可靠性:通过持久化保证消息不丢失。
-
异步性:提高系统的响应能力和吞吐量。
-
削峰填谷:当短时间内产生大量请求时,队列可以将其缓冲起来,让接收方按照自己的能力逐步处理,防止系统被压垮。
典型应用场景
-
工作流处理:用户提交一个订单,系统向队列发送一条"新订单"消息。后端的库存管理、物流计算等系统可以各自从队列中获取消息并进行处理,无需用户等待所有流程完成。
-
系统集成:连接两个不同的、不易直接通信的旧系统。系统A将数据发送到队列,系统B从队列中读取。
-
延迟操作:例如,一个网站需要在用户注册24小时后发送一封提醒邮件。它可以将"发送邮件"消息放入队列,并设置其24小时后才可被接收。
总结
MSMQ 不是一种实时、同步的通信方式(像管道或WCF的NetTcp那样),而是一种强调可靠性、稳定性和系统解耦的异步通信机制。 它适用于那些你希望确保消息最终一定能被处理,但不要求立即得到响应的场景。
目录:
1.源码分析
2.所有源码
3.效果演示
一、源码分析
启用MSMQ Windows功能
Windows 10/11 启用步骤:
-
按
Win + R
键,输入optionalfeatures.exe
回车 -
在"Windows功能"对话框中,找到 "Microsoft Message Queue (MSMQ) 服务器"
-
展开这个选项,勾选所有子项
-
点击"确定",等待安装完成
-
重启计算机

添加引用System.Messaging;

服务器端函数分析
-
构造函数 ServerForm()
public ServerForm()
{
InitializeComponent();
InitializeMSMQ();
}
功能:窗体初始化
调用界面组件初始化
启动MSMQ初始化过程
是整个服务器应用的入口点
-
InitializeMSMQ()
private void InitializeMSMQ()
{
// 创建或连接到消息队列
if (!MessageQueue.Exists(QueuePath))
{
mq = MessageQueue.Create(QueuePath);
AppendLog("创建新的消息队列: " + QueuePath);
}
else
{
mq = new MessageQueue(QueuePath);
AppendLog("连接到现有消息队列: " + QueuePath);
}// 设置消息格式 mq.Formatter = new XmlMessageFormatter(new Type[] { typeof(string) }); // 异步开始接收消息 StartReceiving();
}
功能:MSMQ系统初始化
队列存在性检查:检查.\Private$\MyTestQueue是否存在
队列创建/连接:不存在则创建,存在则连接
消息格式化:设置为XML格式,只处理string类型消息
启动消息监听:开始异步接收消息
日志记录:记录初始化过程
-
StartReceiving()
private void StartReceiving()
{
mq.BeginReceive(TimeSpan.FromSeconds(1), mq, OnMessageReceived);
}
功能:启动异步消息接收
异步操作:使用BeginReceive非阻塞接收
超时设置:1秒超时,避免永久阻塞
回调指定:收到消息时调用OnMessageReceived
状态对象:传递mq对象作为状态参数
-
OnMessageReceived(IAsyncResult result)
private void OnMessageReceived(IAsyncResult result)
{
try
{
System.Messaging.Message message = mq.EndReceive(result);// 在UI线程上更新界面 this.Invoke(new Action(() => { string messageBody = message.Body.ToString(); AppendLog($"收到消息: {messageBody}"); txtReceivedMessages.AppendText(messageBody + Environment.NewLine); // 自动回复 if (chkAutoReply.Checked) { SendReply($"自动回复: 已收到你的消息 '{messageBody}'"); } })); // 继续接收下一条消息 StartReceiving(); } catch (MessageQueueException ex) { this.Invoke(new Action(() => AppendLog($"接收消息错误: {ex.Message}"))); }
}
功能:消息到达回调处理
消息提取:调用EndReceive完成异步操作,获取消息
线程安全:使用Invoke在UI线程更新界面
消息显示:在日志和接收消息框显示内容
自动回复:根据复选框状态自动回复客户端
循环接收:递归调用StartReceiving继续监听
异常处理:捕获MSMQ特定异常并记录
-
SendReply(string replyText)
private void SendReply(string replyText)
{
try
{
using (MessageQueue replyQueue = new MessageQueue(@".\Private\ClientQueue")) { if (!MessageQueue.Exists(@".\Private\ClientQueue"))
{
MessageQueue.Create(@".\Private$\ClientQueue");
}System.Messaging.Message replyMessage = new System.Messaging.Message(replyText); replyQueue.Send(replyMessage); AppendLog($"发送回复: {replyText}"); } } catch (Exception ex) { AppendLog($"发送回复失败: {ex.Message}"); }
}
功能:向客户端发送回复消息
队列准备:检查并创建客户端队列(如果需要)
消息创建:创建包含回复文本的消息对象
消息发送:通过客户端队列发送消息
资源管理:使用using语句确保队列正确释放
错误处理:捕获发送过程中的异常
-
SendToClient(string message)
private void SendToClient(string message)
{
try
{
using (MessageQueue clientQueue = new MessageQueue(@".\Private\ClientQueue")) { if (!MessageQueue.Exists(@".\Private\ClientQueue"))
{
MessageQueue.Create(@".\Private$\ClientQueue");
}System.Messaging.Message msg = new System.Messaging.Message(message); clientQueue.Send(msg); AppendLog($"发送到客户端: {message}"); } } catch (Exception ex) { AppendLog($"发送到客户端失败: {ex.Message}"); }
}
功能:主动向客户端发送消息
手动发送:不同于自动回复,这是服务器主动发起的通信
队列管理:同样确保客户端队列存在
消息构建发送:创建并发送消息
日志记录:记录发送操作
-
AppendLog(string log)
private void AppendLog(string log)
{
string timestamp = DateTime.Now.ToString("HH:mm:ss");
txtLog.AppendText($"[{timestamp}] {log}{Environment.NewLine}");
}
功能:日志记录工具函数
时间戳:为每条日志添加当前时间
格式统一:统一的日志格式 [时间] 内容
界面更新:直接追加到日志文本框
客户端函数分析
-
CheckMSMQAvailability()
private void CheckMSMQAvailability()
{
try
{
if (!IsMSMQAvailable())
{
// 错误处理和用户指导
AppendLog("MSMQ功能未安装!");
AppendLog("请启用Windows MSMQ功能:");
// ... 详细指导信息
btnSendToServer.Enabled = false;
btnCheckServer.Enabled = false;
txtMessageToServer.Enabled = false;
return;
}AppendLog("MSMQ功能可用,正在初始化..."); InitializeMSMQ(); } catch (Exception ex) { AppendLog($"检查MSMQ可用性失败: {ex.Message}"); }
}
功能:MSMQ环境预检查
功能检测:调用IsMSMQAvailable()检测MSMQ是否可用
用户引导:提供详细的安装指导
界面控制:禁用相关功能按钮
错误处理:捕获检测过程中的异常
-
IsMSMQAvailable()
private bool IsMSMQAvailable()
{
try
{
string testPath = @".\Private$\MSMQTestQueue_" + Guid.NewGuid().ToString("N");
bool exists = MessageQueue.Exists(testPath);if (!exists) { using (var testQueue = MessageQueue.Create(testPath, false)) { // 创建成功 } MessageQueue.Delete(testPath); } else { MessageQueue.Delete(testPath); } return true; } catch { return false; }
}
功能:MSMQ功能可用性测试
唯一性测试:使用GUID创建唯一测试队列名,避免冲突
完整流程测试:测试队列创建、存在性检查、删除等完整操作
异常检测:通过try-catch检测任何MSMQ相关异常
资源清理:确保测试队列被正确清理
-
CheckServerStatus()
private void CheckServerStatus()
{
try
{
if (MessageQueue.Exists(ServerQueuePath))
{
AppendLog("服务器状态: ✅ 在线");
btnSendToServer.Enabled = true;
txtMessageToServer.Enabled = true;
lblServerStatus.Text = "服务器状态: 在线";
lblServerStatus.ForeColor = Color.Green;
}
else
{
AppendLog("服务器状态: ❌ 离线");
btnSendToServer.Enabled = false;
lblServerStatus.Text = "服务器状态: 离线";
lblServerStatus.ForeColor = Color.Red;
}
}
catch (Exception ex)
{
AppendLog($"检查服务器状态失败: {ex.Message}");
}
}
功能:服务器连接状态检查
队列存在性检查:检查服务器队列是否存在
界面状态更新:更新按钮启用状态和标签显示
视觉反馈:使用颜色区分在线/离线状态
日志记录:记录状态检查结果
-
SendToServer(string message)
private void SendToServer(string message)
{
try
{
if (!MessageQueue.Exists(ServerQueuePath))
{
AppendLog("错误:服务器队列不存在,请先启动服务器");
MessageBox.Show("服务器队列不存在,请先启动服务器程序", "错误",
MessageBoxButtons.OK, MessageBoxIcon.Error);
btnSendToServer.Enabled = false;
return;
}using (MessageQueue serverQueue = new MessageQueue(ServerQueuePath)) { serverQueue.Formatter = new XmlMessageFormatter(new Type[] { typeof(string) }); System.Messaging.Message msg = new System.Messaging.Message(message); serverQueue.Send(msg); AppendLog($"发送到服务器: {message}"); // 添加到发送历史 txtSentMessages.AppendText($"[{DateTime.Now:HH:mm:ss}] {message}{Environment.NewLine}"); txtSentMessages.SelectionStart = txtSentMessages.Text.Length; txtSentMessages.ScrollToCaret(); } } catch (MessageQueueException ex) { AppendLog($"发送到服务器失败 - 队列错误: {ex.Message}"); btnSendToServer.Enabled = false; } catch (Exception ex) { AppendLog($"发送到服务器失败: {ex.Message}"); }
}
功能:向服务器发送消息
前置检查:发送前确认服务器队列存在
格式设置:确保消息格式化器正确设置
消息发送:创建并发送消息到服务器队列
发送历史:记录到发送历史文本框
自动滚动:滚动到最新消息
错误处理:区分MSMQ异常和一般异常
-
重试机制函数
private void StartReceiving()
{
try
{
mq.BeginReceive(TimeSpan.FromSeconds(1), mq, OnMessageReceived);
}
catch (Exception ex)
{
AppendLog($"开始接收消息失败: {ex.Message}");
// 3秒后重试
System.Threading.Timer timer = null;
timer = new System.Threading.Timer(_ =>
{
StartReceiving();
timer?.Dispose();
}, null, 3000, System.Threading.Timeout.Infinite);
}
}
功能:带重试的消息接收启动
异常恢复:接收启动失败时自动重试
延迟重试:3秒后重新尝试启动接收
资源管理:使用一次性定时器,完成后立即释放
避免循环:确保重试逻辑不会无限循环
二、所有源码
服务器端ServerForm.cs源码
using System;
using System.Messaging;
using System.Windows.Forms;
using System.Text;
namespace MSMQServer
{
public partial class ServerForm : Form
{
private MessageQueue mq;
private const string QueuePath = @".\Private$\MyTestQueue";
public ServerForm()
{
InitializeComponent();
InitializeMSMQ();
}
private void InitializeMSMQ()
{
// 创建或连接到消息队列
if (!MessageQueue.Exists(QueuePath))
{
mq = MessageQueue.Create(QueuePath);
AppendLog("创建新的消息队列: " + QueuePath);
}
else
{
mq = new MessageQueue(QueuePath);
AppendLog("连接到现有消息队列: " + QueuePath);
}
// 设置消息格式
mq.Formatter = new XmlMessageFormatter(new Type[] { typeof(string) });
// 异步开始接收消息
StartReceiving();
}
private void StartReceiving()
{
mq.BeginReceive(TimeSpan.FromSeconds(1), mq, OnMessageReceived);
}
private void OnMessageReceived(IAsyncResult result)
{
try
{
System.Messaging.Message message = mq.EndReceive(result);
// 在UI线程上更新界面
this.Invoke(new Action(() =>
{
string messageBody = message.Body.ToString();
AppendLog($"收到消息: {messageBody}");
txtReceivedMessages.AppendText(messageBody + Environment.NewLine);
// 自动回复
if (chkAutoReply.Checked)
{
SendReply($"自动回复: 已收到你的消息 '{messageBody}'");
}
}));
// 继续接收下一条消息
StartReceiving();
}
catch (MessageQueueException ex)
{
this.Invoke(new Action(() =>
AppendLog($"接收消息错误: {ex.Message}")));
}
}
private void SendReply(string replyText)
{
try
{
using (MessageQueue replyQueue = new MessageQueue(@".\Private$\ClientQueue"))
{
if (!MessageQueue.Exists(@".\Private$\ClientQueue"))
{
MessageQueue.Create(@".\Private$\ClientQueue");
}
System.Messaging.Message replyMessage = new System.Messaging.Message(replyText);
replyQueue.Send(replyMessage);
AppendLog($"发送回复: {replyText}");
}
}
catch (Exception ex)
{
AppendLog($"发送回复失败: {ex.Message}");
}
}
private void btnSendToClient_Click(object sender, EventArgs e)
{
if (!string.IsNullOrEmpty(txtMessageToClient.Text))
{
SendToClient(txtMessageToClient.Text);
txtMessageToClient.Clear();
}
}
private void SendToClient(string message)
{
try
{
using (MessageQueue clientQueue = new MessageQueue(@".\Private$\ClientQueue"))
{
if (!MessageQueue.Exists(@".\Private$\ClientQueue"))
{
MessageQueue.Create(@".\Private$\ClientQueue");
}
System.Messaging.Message msg = new System.Messaging.Message(message);
clientQueue.Send(msg);
AppendLog($"发送到客户端: {message}");
}
}
catch (Exception ex)
{
AppendLog($"发送到客户端失败: {ex.Message}");
}
}
private void AppendLog(string log)
{
string timestamp = DateTime.Now.ToString("HH:mm:ss");
txtLog.AppendText($"[{timestamp}] {log}{Environment.NewLine}");
}
protected override void OnFormClosing(FormClosingEventArgs e)
{
mq?.Close();
mq?.Dispose();
base.OnFormClosing(e);
}
}
}
服务器端ServerForm.designer.cs源码
using System;
using System.Windows.Forms;
namespace MSMQServer
{
partial class ServerForm
{
private System.ComponentModel.IContainer components = null;
private TextBox txtLog;
private TextBox txtReceivedMessages;
private TextBox txtMessageToClient;
private Button btnSendToClient;
private CheckBox chkAutoReply;
private void InitializeComponent()
{
this.txtLog = new TextBox();
this.txtReceivedMessages = new TextBox();
this.txtMessageToClient = new TextBox();
this.btnSendToClient = new Button();
this.chkAutoReply = new CheckBox();
// 布局代码
this.SuspendLayout();
// txtLog - 显示操作日志
this.txtLog.Multiline = true;
this.txtLog.ScrollBars = ScrollBars.Vertical;
this.txtLog.Location = new System.Drawing.Point(12, 12);
this.txtLog.Size = new System.Drawing.Size(400, 150);
this.txtLog.ReadOnly = true;
// txtReceivedMessages - 显示接收到的消息
this.txtReceivedMessages.Multiline = true;
this.txtReceivedMessages.ScrollBars = ScrollBars.Vertical;
this.txtReceivedMessages.Location = new System.Drawing.Point(12, 180);
this.txtReceivedMessages.Size = new System.Drawing.Size(400, 100);
this.txtReceivedMessages.ReadOnly = true;
// 发送消息区域
this.txtMessageToClient.Location = new System.Drawing.Point(12, 300);
this.txtMessageToClient.Size = new System.Drawing.Size(300, 20);
this.btnSendToClient.Location = new System.Drawing.Point(320, 298);
this.btnSendToClient.Size = new System.Drawing.Size(75, 23);
this.btnSendToClient.Text = "发送到客户端";
this.btnSendToClient.Click += new EventHandler(this.btnSendToClient_Click);
this.chkAutoReply.Location = new System.Drawing.Point(12, 330);
this.chkAutoReply.Size = new System.Drawing.Size(150, 20);
this.chkAutoReply.Text = "自动回复客户端";
this.chkAutoReply.Checked = true;
this.Text = "MSMQ 服务器";
this.Size = new System.Drawing.Size(450, 400);
this.Controls.AddRange(new Control[] {
txtLog, txtReceivedMessages, txtMessageToClient,
btnSendToClient, chkAutoReply
});
this.ResumeLayout(false);
}
}
}
客户端ClientForm.cs源码
using System;
using System.Messaging;
using System.Windows.Forms;
using System.Drawing;
using System.Text;
namespace MSMQClient
{
public partial class ClientForm : Form
{
private MessageQueue mq;
private const string QueuePath = @".\Private$\ClientQueue";
private const string ServerQueuePath = @".\Private$\MyTestQueue";
public ClientForm()
{
InitializeComponent();
CheckMSMQAvailability();
}
private void CheckMSMQAvailability()
{
try
{
if (!IsMSMQAvailable())
{
AppendLog("MSMQ功能未安装!");
AppendLog("请启用Windows MSMQ功能:");
AppendLog("1. 按 Win+R,输入 optionalfeatures.exe");
AppendLog("2. 找到并启用 'Microsoft Message Queue (MSMQ) 服务器'");
AppendLog("3. 重启计算机后重新运行程序");
btnSendToServer.Enabled = false;
btnCheckServer.Enabled = false;
txtMessageToServer.Enabled = false;
MessageBox.Show(
"MSMQ功能未安装!\n\n" +
"请按以下步骤启用:\n" +
"1. 按 Win+R,输入 optionalfeatures.exe\n" +
"2. 找到并启用 'Microsoft Message Queue (MSMQ) 服务器'\n" +
"3. 重启计算机后重新运行程序",
"MSMQ未安装",
MessageBoxButtons.OK,
MessageBoxIcon.Warning);
return;
}
AppendLog("MSMQ功能可用,正在初始化...");
InitializeMSMQ();
}
catch (Exception ex)
{
AppendLog($"检查MSMQ可用性失败: {ex.Message}");
}
}
private bool IsMSMQAvailable()
{
try
{
// 尝试使用MessageQueue来检测MSMQ是否可用
string testPath = @".\Private$\MSMQTestQueue_" + Guid.NewGuid().ToString("N");
bool exists = MessageQueue.Exists(testPath);
if (!exists)
{
// 尝试创建测试队列
using (var testQueue = MessageQueue.Create(testPath, false))
{
// 创建成功
}
// 删除测试队列
MessageQueue.Delete(testPath);
}
else
{
// 如果已存在,删除它
MessageQueue.Delete(testPath);
}
return true;
}
catch
{
return false;
}
}
private void InitializeMSMQ()
{
try
{
// 创建或连接到客户端消息队列
if (!MessageQueue.Exists(QueuePath))
{
mq = MessageQueue.Create(QueuePath);
AppendLog("创建客户端消息队列: " + QueuePath);
}
else
{
mq = new MessageQueue(QueuePath);
AppendLog("连接到现有客户端消息队列: " + QueuePath);
}
// 设置消息格式
mq.Formatter = new XmlMessageFormatter(new Type[] { typeof(string) });
// 检查服务器队列是否存在
CheckServerStatus();
// 异步开始接收消息
StartReceiving();
AppendLog("客户端初始化完成,可以开始通信");
}
catch (Exception ex)
{
AppendLog($"初始化MSMQ失败: {ex.Message}");
}
}
private void StartReceiving()
{
try
{
mq.BeginReceive(TimeSpan.FromSeconds(1), mq, OnMessageReceived);
}
catch (Exception ex)
{
AppendLog($"开始接收消息失败: {ex.Message}");
// 3秒后重试
System.Threading.Timer timer = null;
timer = new System.Threading.Timer(_ =>
{
StartReceiving();
timer?.Dispose();
}, null, 3000, System.Threading.Timeout.Infinite);
}
}
private void OnMessageReceived(IAsyncResult result)
{
try
{
System.Messaging.Message message = mq.EndReceive(result);
// 在UI线程上更新界面
this.Invoke(new Action(() =>
{
string messageBody = message.Body.ToString();
AppendLog($"收到服务器回复: {messageBody}");
txtReceivedMessages.AppendText($"[{DateTime.Now:HH:mm:ss}] {messageBody}{Environment.NewLine}");
// 滚动到最新消息
txtReceivedMessages.SelectionStart = txtReceivedMessages.Text.Length;
txtReceivedMessages.ScrollToCaret();
}));
// 继续接收下一条消息
StartReceiving();
}
catch (MessageQueueException ex)
{
this.Invoke(new Action(() =>
AppendLog($"接收消息错误: {ex.Message}")));
}
catch (Exception ex)
{
this.Invoke(new Action(() =>
AppendLog($"处理消息错误: {ex.Message}")));
}
}
private void btnSendToServer_Click(object sender, EventArgs e)
{
if (!string.IsNullOrEmpty(txtMessageToServer.Text.Trim()))
{
SendToServer(txtMessageToServer.Text.Trim());
txtMessageToServer.Clear();
txtMessageToServer.Focus();
}
else
{
MessageBox.Show("请输入要发送的消息", "提示", MessageBoxButtons.OK, MessageBoxIcon.Warning);
}
}
private void SendToServer(string message)
{
try
{
if (!MessageQueue.Exists(ServerQueuePath))
{
AppendLog("错误:服务器队列不存在,请先启动服务器");
MessageBox.Show("服务器队列不存在,请先启动服务器程序", "错误",
MessageBoxButtons.OK, MessageBoxIcon.Error);
btnSendToServer.Enabled = false;
return;
}
using (MessageQueue serverQueue = new MessageQueue(ServerQueuePath))
{
serverQueue.Formatter = new XmlMessageFormatter(new Type[] { typeof(string) });
System.Messaging.Message msg = new System.Messaging.Message(message);
serverQueue.Send(msg);
AppendLog($"发送到服务器: {message}");
// 添加到发送历史
txtSentMessages.AppendText($"[{DateTime.Now:HH:mm:ss}] {message}{Environment.NewLine}");
txtSentMessages.SelectionStart = txtSentMessages.Text.Length;
txtSentMessages.ScrollToCaret();
}
}
catch (MessageQueueException ex)
{
AppendLog($"发送到服务器失败 - 队列错误: {ex.Message}");
btnSendToServer.Enabled = false;
}
catch (Exception ex)
{
AppendLog($"发送到服务器失败: {ex.Message}");
}
}
private void txtMessageToServer_KeyPress(object sender, KeyPressEventArgs e)
{
if (e.KeyChar == (char)Keys.Enter)
{
btnSendToServer_Click(sender, e);
e.Handled = true;
}
}
private void btnClearLog_Click(object sender, EventArgs e)
{
txtLog.Clear();
AppendLog("日志已清空");
}
private void btnClearReceived_Click(object sender, EventArgs e)
{
txtReceivedMessages.Clear();
AppendLog("接收消息已清空");
}
private void btnClearSent_Click(object sender, EventArgs e)
{
txtSentMessages.Clear();
AppendLog("发送历史已清空");
}
private void btnCheckServer_Click(object sender, EventArgs e)
{
CheckServerStatus();
}
private void CheckServerStatus()
{
try
{
if (MessageQueue.Exists(ServerQueuePath))
{
AppendLog("服务器状态: ✅ 在线");
btnSendToServer.Enabled = true;
txtMessageToServer.Enabled = true;
lblServerStatus.Text = "服务器状态: 在线";
lblServerStatus.ForeColor = Color.Green;
}
else
{
AppendLog("服务器状态: ❌ 离线");
btnSendToServer.Enabled = false;
lblServerStatus.Text = "服务器状态: 离线";
lblServerStatus.ForeColor = Color.Red;
}
}
catch (Exception ex)
{
AppendLog($"检查服务器状态失败: {ex.Message}");
}
}
private void AppendLog(string log)
{
string timestamp = DateTime.Now.ToString("HH:mm:ss");
if (txtLog.TextLength > 10000) // 防止日志过长
{
txtLog.Clear();
}
txtLog.AppendText($"[{timestamp}] {log}{Environment.NewLine}");
// 自动滚动到最新日志
txtLog.SelectionStart = txtLog.Text.Length;
txtLog.ScrollToCaret();
}
private void btnReconnect_Click(object sender, EventArgs e)
{
AppendLog("重新连接MSMQ...");
CheckMSMQAvailability();
}
protected override void OnFormClosing(FormClosingEventArgs e)
{
try
{
mq?.Close();
mq?.Dispose();
}
catch (Exception ex)
{
MessageBox.Show($"关闭时发生错误: {ex.Message}", "错误",
MessageBoxButtons.OK, MessageBoxIcon.Error);
}
base.OnFormClosing(e);
}
}
}
客户端ClientForm.designer.cs源码
using System;
using System.Drawing;
using System.Windows.Forms;
namespace MSMQClient
{
partial class ClientForm
{
private System.ComponentModel.IContainer components = null;
private TextBox txtLog;
private TextBox txtReceivedMessages;
private TextBox txtSentMessages;
private TextBox txtMessageToServer;
private Button btnSendToServer;
private Button btnClearLog;
private Button btnClearReceived;
private Button btnClearSent;
private Button btnCheckServer;
private Button btnReconnect;
private Label lblMessageToServer;
private Label lblReceivedMessages;
private Label lblSentMessages;
private Label lblLog;
private Label lblServerStatus;
private Label lblTitle;
private Panel panel1;
private Panel panel2;
private Panel panel3;
private Panel panel4;
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
private void InitializeComponent()
{
this.components = new System.ComponentModel.Container();
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(784, 661);
this.Text = "MSMQ 客户端";
this.StartPosition = FormStartPosition.CenterScreen;
this.MinimumSize = new Size(800, 700);
InitializeControls();
SetupLayout();
}
private void InitializeControls()
{
// 标题
this.lblTitle = new Label();
this.lblTitle.Text = "MSMQ 客户端通信程序";
this.lblTitle.Font = new Font("微软雅黑", 14F, FontStyle.Bold);
this.lblTitle.ForeColor = Color.DarkBlue;
this.lblTitle.TextAlign = ContentAlignment.MiddleCenter;
this.lblTitle.Location = new Point(12, 10);
this.lblTitle.Size = new Size(760, 30);
// 服务器状态标签
this.lblServerStatus = new Label();
this.lblServerStatus.Text = "服务器状态: 检测中...";
this.lblServerStatus.Font = new Font("微软雅黑", 10F, FontStyle.Bold);
this.lblServerStatus.ForeColor = Color.Orange;
this.lblServerStatus.Location = new Point(12, 45);
this.lblServerStatus.Size = new Size(200, 20);
// 日志文本框
this.txtLog = new TextBox();
this.txtLog.Multiline = true;
this.txtLog.ScrollBars = ScrollBars.Vertical;
this.txtLog.Location = new Point(12, 80);
this.txtLog.Size = new Size(760, 120);
this.txtLog.ReadOnly = true;
this.txtLog.BackColor = Color.White;
this.txtLog.Font = new Font("Consolas", 9F);
// 接收到的消息文本框
this.txtReceivedMessages = new TextBox();
this.txtReceivedMessages.Multiline = true;
this.txtReceivedMessages.ScrollBars = ScrollBars.Vertical;
this.txtReceivedMessages.Location = new Point(12, 235);
this.txtReceivedMessages.Size = new Size(760, 120);
this.txtReceivedMessages.ReadOnly = true;
this.txtReceivedMessages.BackColor = Color.LightYellow;
this.txtReceivedMessages.Font = new Font("微软雅黑", 9F);
// 已发送的消息文本框
this.txtSentMessages = new TextBox();
this.txtSentMessages.Multiline = true;
this.txtSentMessages.ScrollBars = ScrollBars.Vertical;
this.txtSentMessages.Location = new Point(12, 390);
this.txtSentMessages.Size = new Size(760, 120);
this.txtSentMessages.ReadOnly = true;
this.txtSentMessages.BackColor = Color.LightCyan;
this.txtSentMessages.Font = new Font("微软雅黑", 9F);
// 消息输入框
this.txtMessageToServer = new TextBox();
this.txtMessageToServer.Location = new Point(12, 545);
this.txtMessageToServer.Size = new Size(500, 23);
this.txtMessageToServer.Font = new Font("微软雅黑", 10F);
// 标签
this.lblLog = new Label();
this.lblLog.Text = "操作日志:";
this.lblLog.Location = new Point(12, 60);
this.lblLog.Size = new Size(100, 20);
this.lblLog.Font = new Font("微软雅黑", 9F, FontStyle.Bold);
this.lblReceivedMessages = new Label();
this.lblReceivedMessages.Text = "从服务器接收的消息:";
this.lblReceivedMessages.Location = new Point(12, 215);
this.lblReceivedMessages.Size = new Size(200, 20);
this.lblReceivedMessages.Font = new Font("微软雅黑", 9F, FontStyle.Bold);
this.lblSentMessages = new Label();
this.lblSentMessages.Text = "已发送到服务器的消息:";
this.lblSentMessages.Location = new Point(12, 370);
this.lblSentMessages.Size = new Size(200, 20);
this.lblSentMessages.Font = new Font("微软雅黑", 9F, FontStyle.Bold);
this.lblMessageToServer = new Label();
this.lblMessageToServer.Text = "发送消息到服务器:";
this.lblMessageToServer.Location = new Point(12, 525);
this.lblMessageToServer.Size = new Size(150, 20);
this.lblMessageToServer.Font = new Font("微软雅黑", 9F, FontStyle.Bold);
// 按钮
this.btnSendToServer = new Button();
this.btnSendToServer.Text = "发送";
this.btnSendToServer.Location = new Point(520, 543);
this.btnSendToServer.Size = new Size(70, 27);
this.btnSendToServer.BackColor = Color.LightBlue;
this.btnSendToServer.Font = new Font("微软雅黑", 9F, FontStyle.Bold);
this.btnSendToServer.UseVisualStyleBackColor = false;
this.btnCheckServer = new Button();
this.btnCheckServer.Text = "检查服务器";
this.btnCheckServer.Location = new Point(600, 543);
this.btnCheckServer.Size = new Size(80, 27);
this.btnCheckServer.BackColor = Color.LightGreen;
this.btnCheckServer.Font = new Font("微软雅黑", 9F);
this.btnCheckServer.UseVisualStyleBackColor = false;
this.btnReconnect = new Button();
this.btnReconnect.Text = "重新连接";
this.btnReconnect.Location = new Point(690, 543);
this.btnReconnect.Size = new Size(80, 27);
this.btnReconnect.BackColor = Color.LightSalmon;
this.btnReconnect.Font = new Font("微软雅黑", 9F);
this.btnReconnect.UseVisualStyleBackColor = false;
this.btnClearLog = new Button();
this.btnClearLog.Text = "清空日志";
this.btnClearLog.Location = new Point(690, 200);
this.btnClearLog.Size = new Size(80, 25);
this.btnClearLog.Font = new Font("微软雅黑", 8F);
this.btnClearLog.UseVisualStyleBackColor = true;
this.btnClearReceived = new Button();
this.btnClearReceived.Text = "清空接收";
this.btnClearReceived.Location = new Point(690, 355);
this.btnClearReceived.Size = new Size(80, 25);
this.btnClearReceived.Font = new Font("微软雅黑", 8F);
this.btnClearReceived.UseVisualStyleBackColor = true;
this.btnClearSent = new Button();
this.btnClearSent.Text = "清空发送";
this.btnClearSent.Location = new Point(690, 510);
this.btnClearSent.Size = new Size(80, 25);
this.btnClearSent.Font = new Font("微软雅黑", 8F);
this.btnClearSent.UseVisualStyleBackColor = true;
}
private void SetupLayout()
{
// 添加控件到表单
this.Controls.Add(this.lblTitle);
this.Controls.Add(this.lblServerStatus);
this.Controls.Add(this.lblLog);
this.Controls.Add(this.txtLog);
this.Controls.Add(this.lblReceivedMessages);
this.Controls.Add(this.txtReceivedMessages);
this.Controls.Add(this.lblSentMessages);
this.Controls.Add(this.txtSentMessages);
this.Controls.Add(this.lblMessageToServer);
this.Controls.Add(this.txtMessageToServer);
this.Controls.Add(this.btnSendToServer);
this.Controls.Add(this.btnCheckServer);
this.Controls.Add(this.btnReconnect);
this.Controls.Add(this.btnClearLog);
this.Controls.Add(this.btnClearReceived);
this.Controls.Add(this.btnClearSent);
// 设置事件处理
this.btnSendToServer.Click += new EventHandler(this.btnSendToServer_Click);
this.btnCheckServer.Click += new EventHandler(this.btnCheckServer_Click);
this.btnReconnect.Click += new EventHandler(this.btnReconnect_Click);
this.btnClearLog.Click += new EventHandler(this.btnClearLog_Click);
this.btnClearReceived.Click += new EventHandler(this.btnClearReceived_Click);
this.btnClearSent.Click += new EventHandler(this.btnClearSent_Click);
this.txtMessageToServer.KeyPress += new KeyPressEventHandler(this.txtMessageToServer_KeyPress);
}
}
}
三、效果演示
先打开服务器,发送 Server to client,关闭以后打开客户端,可以看到接收到数据。
客户端发送 client to server,打开服务器,可以看到接收到数据。
