文章的目的为了记录使用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.效果演示
一、源码分析
架构设计分析
- 整体架构
┌─────────────────┐ 命名管道通信 ┌─────────────────┐
│ 服务端程序 │ ←─────────────→ │ 客户端程序 │
│ │ │ │
│ - 管道服务器 │ │ - 管道客户端 │
│ - 消息监听 │ │ - 消息发送 │
│ - 连接管理 │ │ - 连接管理 │
└─────────────────┘ └─────────────────┘
- 通信流程
服务端启动 → 监听连接 → 客户端连接 → 建立通信通道 → 双向消息传递
核心技术实现分析
服务端核心代码分析
-
管道服务器初始化
pipeServer = new NamedPipeServerStream(
"TestPipe", // 管道名称
PipeDirection.InOut, // 双向通信
1, // 最大实例数
PipeTransmissionMode.Message, // 消息模式
PipeOptions.Asynchronous // 异步操作
);
关键参数说明:
PipeDirection.InOut: 支持双向通信
最大实例数1: 只允许一个客户端连接
Message模式: 以消息为单位传输,保持消息边界
Asynchronous: 支持异步操作,提高性能
-
连接处理循环
while (!cancellationToken.IsCancellationRequested)
{
pipeServer.WaitForConnection(); // 阻塞等待客户端连接
LogStatus("客户端已连接");// 启动消息接收任务 Task.Run(() => ReceiveMessages(cancellationToken)); // 保持连接状态 while (pipeServer.IsConnected && !cancellationToken.IsCancellationRequested) { Thread.Sleep(100); }
}
设计优点:
使用CancellationToken支持优雅停止
分离连接管理和消息处理
自动重连机制
-
消息接收机制
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;
}
}
}
三、效果演示
