C#管道通讯及传输信息丢失的原因

发布于:2025-05-08 ⋅ 阅读:(19) ⋅ 点赞:(0)

以下是C#管道通讯客户端/服务端共用类

namespace PipeCommunication
{
    /// <summary>
    /// 管道信息回调通知
    /// </summary>
    /// <param name="msg"></param>
    public delegate void PipeMessageEventHandler(string msg);

    public class PipeCommunicateCenter
    {
        public event PipeMessageEventHandler OnPipeMessageReceiveEvent;

        private string _pipeServerName = "";
        private string _pipeClientName = "";

        public PipeCommunicateCenter(string pipeServerName, string pipeClientName)
        {
            _pipeServerName = pipeServerName;
            _pipeClientName = pipeClientName;
        }

        /// <summary>
        /// 发送消息
        /// </summary>
        /// <param name="msg"></param>
        public void ClientSend(string msg)
        {
            try
            {
                using (NamedPipeClientStream pipeClient = new NamedPipeClientStream(".", _pipeClientName, PipeDirection.InOut))
                {
                    pipeClient.Connect(3000);

                    using (StreamWriter sw = new StreamWriter(pipeClient))
                    {
                        sw.AutoFlush = true;
                        sw.WriteLine(msg);
                    }
                }
            }
            catch (Exception ex)
            {

            }
        }

        Thread thPipLsiten;
        /// <summary>
        /// 启动监听
        /// </summary>
        public void StartPipListen()
        {
            thPipLsiten = new Thread(PipListen);
            thPipLsiten.IsBackground = true;
            thPipLsiten.Start();
        }

        /// <summary>
        /// 监听线程是否存在
        /// </summary>
        /// <returns></returns>
        public bool GetPipListenIsAlive()
        {
            return thPipLsiten == null ? false : thPipLsiten.IsAlive;
        }

        bool hasRead = false;
        /// <summary>
        /// 监听线程
        /// </summary>
        private void PipListen()
        {
            try
            {
                while (!isExist)
                {
                    using (NamedPipeServerStream pipeServer = new NamedPipeServerStream(_pipeServerName, PipeDirection.InOut))
                    {
                        pipeServer.WaitForConnection();//等待连接,程序会阻塞在此处,直到有一个连接到达
                        hasRead = false;
                        try
                        {
                            while (!hasRead)
                            {
                                using (StreamReader sr = new StreamReader(pipeServer))
                                {
                                    var read = sr.ReadLine();
                                    if (!string.IsNullOrEmpty(read))
                                    {
                                        hasRead = true;
                                        //MessageBox.Show("pipread:" + read);
                                        NotifyPipeMessageReceive(read);
                                    }
                                }
                                Thread.Sleep(10);
                            }
                        }
                        catch (Exception ex2)
                        {

                        }
                    }
                    Thread.Sleep(10);
                }
            }
            catch (Exception ex1)
            {

            }

        }

        /// <summary>
        /// 通知收到信息
        /// </summary>
        /// <param name="msg"></param>
        private void NotifyPipeMessageReceive(string msg)
        {
            OnPipeMessageReceiveEvent?.Invoke(msg);
        }

        bool isExist = false;
        /// <summary>
        /// 退出监听管道
        /// </summary>
        public void ExistPipeCommunicate()
        {
            isExist = true;
        }
    }
}

使用条件:

客户端/服务端通讯均在线程中使用

问题:

在使用过程中偶尔发生通讯丢失,程式假死,程式逻辑无法正常走下去.

原因分析:

因为程式中异步线程使用了Application.DoEvents()方法.

在C# WinForms中,Application.DoEvents() 方法的作用是强制处理当前消息队列中的所有Windows消息,例如用户输入(点击、键盘事件)、界面重绘等。它的主要意义是让应用程序在长时间运行的代码中保持界面响应,但需谨慎使用。

当执行耗时操作(如循环、复杂计算或阻塞任务)时,UI线程会被占用,导致界面“卡死”(无法响应用户操作或更新显示)。调用 Application.DoEvents() 会临时处理消息队列中的事件,让界面保持“假响应”。

解决方案:

在非UI线程中禁止使用 Application.DoEvents()

异步线程强制使用 Application.DoEvents()可能会导致事件处理顺序混乱,界面更新异常,逻辑依赖破坏等问题.


网站公告

今日签到

点亮在社区的每一天
去签到