开源 C# 快速开发(十三)进程--管道通讯
文章的目的为了记录使用C# 开发学习的经历。开发流程和要点有些记忆模糊,赶紧记录,防止忘记。
相关链接:
开源 C# 快速开发(一)基础知识
开源 C# 快速开发(二)基础控件
开源 C# 快速开发(三)复杂控件
开源 C# 快速开发(四)自定义控件--波形图
开源 C# 快速开发(五)自定义控件--仪表盘
开源 C# 快速开发(六)自定义控件--圆环
开源 C# 快速开发(七)通讯--串口
开源 C# 快速开发(八)通讯--Tcp服务器端
开源 C# 快速开发(九)通讯--Tcp客户端
开源 C# 快速开发(十)通讯--http客户端
开源 C# 快速开发(十一)线程
开源 C# 快速开发(十二)进程监控
推荐链接:
开源 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博客
本章节主要内容是:进程之间的命名管道服务器和客户端程序。
目录:
1.源码分析
2.所有源码
3.效果演示
一、源码分析
架构设计分析
1. 整体架构
┌─────────────────┐ 命名管道通信 ┌─────────────────┐
│ 服务端程序 │ ←─────────────→ │ 客户端程序 │
│ │ │ │
│ - 管道服务器 │ │ - 管道客户端 │
│ - 消息监听 │ │ - 消息发送 │
│ - 连接管理 │ │ - 连接管理 │
└─────────────────┘ └─────────────────┘
2. 通信流程
服务端启动 → 监听连接 → 客户端连接 → 建立通信通道 → 双向消息传递
核心技术实现分析
服务端核心代码分析
1. 管道服务器初始化
pipeServer = new NamedPipeServerStream("TestPipe", // 管道名称PipeDirection.InOut, // 双向通信1, // 最大实例数PipeTransmissionMode.Message, // 消息模式PipeOptions.Asynchronous // 异步操作
);
关键参数说明:
PipeDirection.InOut: 支持双向通信
最大实例数1: 只允许一个客户端连接
Message模式: 以消息为单位传输,保持消息边界
Asynchronous: 支持异步操作,提高性能
2. 连接处理循环
while (!cancellationToken.IsCancellationRequested)
{pipeServer.WaitForConnection(); // 阻塞等待客户端连接LogStatus("客户端已连接");// 启动消息接收任务Task.Run(() => ReceiveMessages(cancellationToken));// 保持连接状态while (pipeServer.IsConnected && !cancellationToken.IsCancellationRequested){Thread.Sleep(100);}
}
设计优点:
使用CancellationToken支持优雅停止
分离连接管理和消息处理
自动重连机制
3. 消息接收机制
private async void ReceiveMessages(CancellationToken cancellationToken)
{byte[] buffer = new byte[1024];StringBuilder messageBuilder = new StringBuilder();while (pipeServer.IsConnected && !cancellationToken.IsCancellationRequested){int bytesRead = await pipeServer.ReadAsync(buffer, 0, buffer.Length, cancellationToken);if (bytesRead > 0){string receivedData = Encoding.UTF8.GetString(buffer, 0, bytesRead);messageBuilder.Append(receivedData);// 消息完整性检查if (receivedData.EndsWith("\n") || !pipeServer.IsMessageComplete){string completeMessage = messageBuilder.ToString().Trim();LogMessage($"客户端: {completeMessage}");messageBuilder.Clear();}}}
}
二、所有源码
NamedPipeServer.cs 服务器端源码
using System;
using System.IO.Pipes;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;namespace NamedPipeServer
{public partial class ServerForm : Form{private NamedPipeServerStream pipeServer;private CancellationTokenSource cancellationTokenSource;private bool isListening = false;public ServerForm(){InitializeComponent();InitializeControls();}private void InitializeControls(){// 窗体设置this.Text = "命名管道服务端";this.Size = new System.Drawing.Size(500, 400);this.StartPosition = FormStartPosition.CenterScreen;// 创建控件var lblStatus = new Label { Text = "服务状态:", Location = new System.Drawing.Point(20, 20), AutoSize = true };var lblLog = new Label { Text = "通信日志:", Location = new System.Drawing.Point(20, 180), AutoSize = true };txtStatus = new TextBox{Location = new System.Drawing.Point(20, 50),Size = new System.Drawing.Size(440, 100),Multiline = true,ReadOnly = true,ScrollBars = ScrollBars.Vertical};txtLog = new TextBox{Location = new System.Drawing.Point(20, 210),Size = new System.Drawing.Size(440, 100),Multiline = true,ReadOnly = true,ScrollBars = ScrollBars.Vertical};txtMessage = new TextBox { Location = new System.Drawing.Point(20, 320), Size = new System.Drawing.Size(300, 23) };btnStart = new Button { Text = "启动服务", Location = new System.Drawing.Point(20, 140), Size = new System.Drawing.Size(80, 30) };btnStop = new Button { Text = "停止服务", Location = new System.Drawing.Point(110, 140), Size = new System.Drawing.Size(80, 30), Enabled = false };btnSend = new Button { Text = "发送消息", Location = new System.Drawing.Point(330, 320), Size = new System.Drawing.Size(80, 30) };// 添加到窗体this.Controls.AddRange(new Control[] { lblStatus, lblLog, txtStatus, txtLog, txtMessage, btnStart, btnStop, btnSend });// 事件绑定btnStart.Click += BtnStart_Click;btnStop.Click += BtnStop_Click;btnSend.Click += BtnSend_Click;this.FormClosing += ServerForm_FormClosing;}// 控件声明private TextBox txtStatus;private TextBox txtLog;private TextBox txtMessage;private Button btnStart;private Button btnStop;private Button btnSend;private async void BtnStart_Click(object sender, EventArgs e){try{cancellationTokenSource = new CancellationTokenSource();isListening = true;btnStart.Enabled = false;btnStop.Enabled = true;btnSend.Enabled = true;LogStatus("服务启动中...");// 启动管道监听await Task.Run(() => StartPipeServer(cancellationTokenSource.Token));}catch (Exception ex){LogStatus($"启动服务失败: {ex.Message}");ResetControls();}}private void BtnStop_Click(object sender, EventArgs e){StopServer();}private void BtnSend_Click(object sender, EventArgs e){SendMessageToClient();}private void ServerForm_FormClosing(object sender, FormClosingEventArgs e){StopServer();}private void StartPipeServer(CancellationToken cancellationToken){try{while (!cancellationToken.IsCancellationRequested){LogStatus("等待客户端连接...");// 创建命名管道服务器pipeServer = new NamedPipeServerStream("TestPipe", PipeDirection.InOut, 1,PipeTransmissionMode.Message, PipeOptions.Asynchronous);// 等待客户端连接pipeServer.WaitForConnection();LogStatus("客户端已连接");LogMessage("系统: 客户端连接成功");// 启动消息接收循环Task.Run(() => ReceiveMessages(cancellationToken));// 保持连接直到客户端断开while (pipeServer.IsConnected && !cancellationToken.IsCancellationRequested){Thread.Sleep(100);}if (pipeServer.IsConnected){pipeServer.Disconnect();}pipeServer.Close();pipeServer.Dispose();LogMessage("系统: 客户端断开连接");}}catch (Exception ex){if (!cancellationToken.IsCancellationRequested){LogStatus($"服务器错误: {ex.Message}");}}}private async void ReceiveMessages(CancellationToken cancellationToken){byte[] buffer = new byte[1024];StringBuilder messageBuilder = new StringBuilder();try{while (pipeServer.IsConnected && !cancellationToken.IsCancellationRequested){if (pipeServer.IsConnected && pipeServer.CanRead){int bytesRead = await pipeServer.ReadAsync(buffer, 0, buffer.Length, cancellationToken);if (bytesRead > 0){string receivedData = Encoding.UTF8.GetString(buffer, 0, bytesRead);messageBuilder.Append(receivedData);// 检查是否收到完整消息(以换行符结尾)if (receivedData.EndsWith("\n") || !pipeServer.IsMessageComplete){string completeMessage = messageBuilder.ToString().Trim();if (!string.IsNullOrEmpty(completeMessage)){LogMessage($"客户端: {completeMessage}");}messageBuilder.Clear();}}}await Task.Delay(10, cancellationToken);}}catch (Exception ex){if (!cancellationToken.IsCancellationRequested){LogMessage($"系统: 接收消息错误 - {ex.Message}");}}}private void SendMessageToClient(){if (string.IsNullOrWhiteSpace(txtMessage.Text))return;if (pipeServer == null || !pipeServer.IsConnected){MessageBox.Show("客户端未连接", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);return;}try{string message = txtMessage.Text + "\n";byte[] buffer = Encoding.UTF8.GetBytes(message);pipeServer.Write(buffer, 0, buffer.Length);pipeServer.Flush();LogMessage($"服务端: {txtMessage.Text}");txtMessage.Clear();}catch (Exception ex){LogMessage($"系统: 发送消息失败 - {ex.Message}");}}private void StopServer(){try{isListening = false;cancellationTokenSource?.Cancel();if (pipeServer != null){if (pipeServer.IsConnected){pipeServer.Disconnect();}pipeServer.Close();pipeServer.Dispose();pipeServer = null;}LogStatus("服务已停止");ResetControls();}catch (Exception ex){LogStatus($"停止服务时出错: {ex.Message}");}}private void LogStatus(string message){if (txtStatus.InvokeRequired){txtStatus.Invoke(new Action<string>(LogStatus), message);return;}txtStatus.AppendText($"[{DateTime.Now:HH:mm:ss}] {message}\r\n");txtStatus.ScrollToCaret();}private void LogMessage(string message){if (txtLog.InvokeRequired){txtLog.Invoke(new Action<string>(LogMessage), message);return;}txtLog.AppendText($"[{DateTime.Now:HH:mm:ss}] {message}\r\n");txtLog.ScrollToCaret();}private void ResetControls(){if (btnStart.InvokeRequired){btnStart.Invoke(new Action(ResetControls));return;}btnStart.Enabled = true;btnStop.Enabled = false;btnSend.Enabled = false;}}
}
NamedPipeClient.cs 客户端源码
using System;
using System.IO.Pipes;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;namespace NamedPipeClient
{public partial class ClientForm : Form{private NamedPipeClientStream pipeClient;private CancellationTokenSource cancellationTokenSource;private bool isConnected = false;public ClientForm(){InitializeComponent();InitializeControls();}private void InitializeControls(){// 窗体设置this.Text = "命名管道客户端";this.Size = new System.Drawing.Size(500, 400);this.StartPosition = FormStartPosition.CenterScreen;// 创建控件var lblStatus = new Label { Text = "连接状态:", Location = new System.Drawing.Point(20, 20), AutoSize = true };var lblLog = new Label { Text = "通信日志:", Location = new System.Drawing.Point(20, 180), AutoSize = true };txtStatus = new TextBox{Location = new System.Drawing.Point(20, 50),Size = new System.Drawing.Size(440, 100),Multiline = true,ReadOnly = true,ScrollBars = ScrollBars.Vertical};txtLog = new TextBox{Location = new System.Drawing.Point(20, 210),Size = new System.Drawing.Size(440, 100),Multiline = true,ReadOnly = true,ScrollBars = ScrollBars.Vertical};txtMessage = new TextBox { Location = new System.Drawing.Point(20, 320), Size = new System.Drawing.Size(300, 23) };btnConnect = new Button { Text = "连接服务", Location = new System.Drawing.Point(20, 140), Size = new System.Drawing.Size(80, 30) };btnDisconnect = new Button { Text = "断开连接", Location = new System.Drawing.Point(110, 140), Size = new System.Drawing.Size(80, 30), Enabled = false };btnSend = new Button { Text = "发送消息", Location = new System.Drawing.Point(330, 320), Size = new System.Drawing.Size(80, 30), Enabled = false };// 添加到窗体this.Controls.AddRange(new Control[] { lblStatus, lblLog, txtStatus, txtLog, txtMessage, btnConnect, btnDisconnect, btnSend });// 事件绑定btnConnect.Click += BtnConnect_Click;btnDisconnect.Click += BtnDisconnect_Click;btnSend.Click += BtnSend_Click;this.FormClosing += ClientForm_FormClosing;}// 控件声明private TextBox txtStatus;private TextBox txtLog;private TextBox txtMessage;private Button btnConnect;private Button btnDisconnect;private Button btnSend;private async void BtnConnect_Click(object sender, EventArgs e){try{cancellationTokenSource = new CancellationTokenSource();btnConnect.Enabled = false;btnDisconnect.Enabled = true;btnSend.Enabled = true;LogStatus("正在连接服务器...");await Task.Run(() => ConnectToServer(cancellationTokenSource.Token));}catch (Exception ex){LogStatus($"连接失败: {ex.Message}");ResetControls();}}private void BtnDisconnect_Click(object sender, EventArgs e){Disconnect();}private void BtnSend_Click(object sender, EventArgs e){SendMessageToServer();}private void ClientForm_FormClosing(object sender, FormClosingEventArgs e){Disconnect();}private void ConnectToServer(CancellationToken cancellationToken){try{pipeClient = new NamedPipeClientStream(".", "TestPipe", PipeDirection.InOut, PipeOptions.Asynchronous);LogStatus("尝试连接服务器...");pipeClient.Connect(5000); // 5秒超时if (pipeClient.IsConnected){isConnected = true;LogStatus("已成功连接到服务器");LogMessage("系统: 连接到服务器成功");// 启动消息接收循环Task.Run(() => ReceiveMessages(cancellationToken));}else{throw new Exception("连接超时或失败");}}catch (TimeoutException){throw new Exception("连接超时,请确保服务器正在运行");}catch (Exception ex){throw new Exception($"连接错误: {ex.Message}");}}private async void ReceiveMessages(CancellationToken cancellationToken){byte[] buffer = new byte[1024];StringBuilder messageBuilder = new StringBuilder();try{while (isConnected && !cancellationToken.IsCancellationRequested){if (pipeClient.IsConnected && pipeClient.CanRead){int bytesRead = await pipeClient.ReadAsync(buffer, 0, buffer.Length, cancellationToken);if (bytesRead > 0){string receivedData = Encoding.UTF8.GetString(buffer, 0, bytesRead);messageBuilder.Append(receivedData);// 检查是否收到完整消息if (receivedData.EndsWith("\n") || !pipeClient.IsMessageComplete){string completeMessage = messageBuilder.ToString().Trim();if (!string.IsNullOrEmpty(completeMessage)){LogMessage($"服务端: {completeMessage}");}messageBuilder.Clear();}}}await Task.Delay(10, cancellationToken);}}catch (Exception ex){if (!cancellationToken.IsCancellationRequested){LogMessage($"系统: 接收消息错误 - {ex.Message}");}}}private void SendMessageToServer(){if (string.IsNullOrWhiteSpace(txtMessage.Text))return;if (pipeClient == null || !pipeClient.IsConnected){MessageBox.Show("未连接到服务器", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);return;}try{string message = txtMessage.Text + "\n";byte[] buffer = Encoding.UTF8.GetBytes(message);pipeClient.Write(buffer, 0, buffer.Length);pipeClient.Flush();LogMessage($"客户端: {txtMessage.Text}");txtMessage.Clear();}catch (Exception ex){LogMessage($"系统: 发送消息失败 - {ex.Message}");}}private void Disconnect(){try{isConnected = false;cancellationTokenSource?.Cancel();if (pipeClient != null){if (pipeClient.IsConnected){pipeClient.Close();}pipeClient.Dispose();pipeClient = null;}LogStatus("已断开连接");ResetControls();}catch (Exception ex){LogStatus($"断开连接时出错: {ex.Message}");}}private void LogStatus(string message){if (txtStatus.InvokeRequired){txtStatus.Invoke(new Action<string>(LogStatus), message);return;}txtStatus.AppendText($"[{DateTime.Now:HH:mm:ss}] {message}\r\n");txtStatus.ScrollToCaret();}private void LogMessage(string message){if (txtLog.InvokeRequired){txtLog.Invoke(new Action<string>(LogMessage), message);return;}txtLog.AppendText($"[{DateTime.Now:HH:mm:ss}] {message}\r\n");txtLog.ScrollToCaret();}private void ResetControls(){if (btnConnect.InvokeRequired){btnConnect.Invoke(new Action(ResetControls));return;}btnConnect.Enabled = true;btnDisconnect.Enabled = false;btnSend.Enabled = false;}}
}
三、效果演示