开源 C# 快速开发(十七)进程--消息队列MSMQ
文章的目的为了记录使用C# 开发学习的经历。开发流程和要点有些记忆模糊,赶紧记录,防止忘记。
相关链接:
开源 C# 快速开发(一)基础知识
开源 C# 快速开发(二)基础控件
开源 C# 快速开发(三)复杂控件
开源 C# 快速开发(四)自定义控件--波形图
开源 C# 快速开发(五)自定义控件--仪表盘
开源 C# 快速开发(六)自定义控件--圆环
开源 C# 快速开发(七)通讯--串口
开源 C# 快速开发(八)通讯--Tcp服务器端
开源 C# 快速开发(九)通讯--Tcp客户端
开源 C# 快速开发(十)通讯--http客户端
开源 C# 快速开发(十一)线程
开源 C# 快速开发(十二)进程监控
开源 C# 快速开发(十三)进程--管道通讯
开源 C# 快速开发(十四)进程--内存映射
开源 C# 快速开发(十五)进程--windows消息
开源 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;
服务器端函数分析
1. 构造函数 ServerForm()
public ServerForm()
{InitializeComponent();InitializeMSMQ();
}
功能:窗体初始化
调用界面组件初始化
启动MSMQ初始化过程
是整个服务器应用的入口点
2. 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类型消息
启动消息监听:开始异步接收消息
日志记录:记录初始化过程
3. StartReceiving()
private void StartReceiving()
{mq.BeginReceive(TimeSpan.FromSeconds(1), mq, OnMessageReceived);
}
功能:启动异步消息接收
异步操作:使用BeginReceive非阻塞接收
超时设置:1秒超时,避免永久阻塞
回调指定:收到消息时调用OnMessageReceived
状态对象:传递mq对象作为状态参数
4. 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特定异常并记录
5. 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语句确保队列正确释放
错误处理:捕获发送过程中的异常
6. 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}");}
}
功能:主动向客户端发送消息
手动发送:不同于自动回复,这是服务器主动发起的通信
队列管理:同样确保客户端队列存在
消息构建发送:创建并发送消息
日志记录:记录发送操作
7. AppendLog(string log)
private void AppendLog(string log)
{string timestamp = DateTime.Now.ToString("HH:mm:ss");txtLog.AppendText($"[{timestamp}] {log}{Environment.NewLine}");
}
功能:日志记录工具函数
时间戳:为每条日志添加当前时间
格式统一:统一的日志格式 [时间] 内容
界面更新:直接追加到日志文本框
客户端函数分析
1. 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是否可用
用户引导:提供详细的安装指导
界面控制:禁用相关功能按钮
错误处理:捕获检测过程中的异常
2. 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相关异常
资源清理:确保测试队列被正确清理
3. 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}");}
}
功能:服务器连接状态检查
队列存在性检查:检查服务器队列是否存在
界面状态更新:更新按钮启用状态和标签显示
视觉反馈:使用颜色区分在线/离线状态
日志记录:记录状态检查结果
4. 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异常和一般异常
5. 重试机制函数
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,打开服务器,可以看到接收到数据。