开源 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. 整体架构

┌─────────────────┐ 命名管道通信 ┌─────────────────┐

│ 服务端程序 │ ←─────────────→ │ 客户端程序 │

│ │ │ │

│ - 管道服务器 │ │ - 管道客户端 │

│ - 消息监听 │ │ - 消息发送 │

│ - 连接管理 │ │ - 连接管理 │

└─────────────────┘ └─────────────────┘

  1. 通信流程

服务端启动 → 监听连接 → 客户端连接 → 建立通信通道 → 双向消息传递

核心技术实现分析

服务端核心代码分析

  1. 管道服务器初始化

    pipeServer = new NamedPipeServerStream(
    "TestPipe", // 管道名称
    PipeDirection.InOut, // 双向通信
    1, // 最大实例数
    PipeTransmissionMode.Message, // 消息模式
    PipeOptions.Asynchronous // 异步操作
    );

关键参数说明:

PipeDirection.InOut: 支持双向通信

最大实例数1: 只允许一个客户端连接

Message模式: 以消息为单位传输,保持消息边界

Asynchronous: 支持异步操作,提高性能

  1. 连接处理循环

    while (!cancellationToken.IsCancellationRequested)
    {
    pipeServer.WaitForConnection(); // 阻塞等待客户端连接
    LogStatus("客户端已连接");

    复制代码
     // 启动消息接收任务
     Task.Run(() => ReceiveMessages(cancellationToken));
     
     // 保持连接状态
     while (pipeServer.IsConnected && !cancellationToken.IsCancellationRequested)
     {
         Thread.Sleep(100);
     }

    }

设计优点:

使用CancellationToken支持优雅停止

分离连接管理和消息处理

自动重连机制

  1. 消息接收机制

    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;
        }
    }
}

三、效果演示

相关推荐
茉莉玫瑰花茶3 小时前
Qt 界面优化 --- 绘图
开发语言·数据库·qt
掘根3 小时前
【Qt】容器类控件——QTabWidget
开发语言·qt
hqwest3 小时前
QT肝8天07--连接数据库
开发语言·数据库·c++·qt·sqlite·上位机·qt开发
ManThink Technology3 小时前
实用的LoRaWAN 应用层协议规范
开发语言·php
敲代码的嘎仔4 小时前
牛客算法基础noob59 简写单词
java·开发语言·数据结构·程序人生·算法·leetcode·学习方法
catchadmin4 小时前
如何在 PHP 升级不踩坑?学会通过阅读 RFC 提前预知版本变化
开发语言·后端·php
tpoog4 小时前
[C++项目组件]Elasticsearch简单介绍
开发语言·c++·elasticsearch
特立独行的猫a6 小时前
C 语言各种指针详解
java·c语言·开发语言
彭于晏Yan7 小时前
MyBatis-Plus使用动态表名分表查询
java·开发语言·mybatis