C#管道通讯及传输信息丢失的原因
以下是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()可能会导致事件处理顺序混乱,界面更新异常,逻辑依赖破坏等问题.
