首页 > 解决方案 > 尝试从 NamedPipeClientStream 写入 NamedPipeServerStream 时如何修复“断管”错误

问题描述

我有一个程序,它必须与另一个从第一个调用的程序通信。我已经设法使用 NamedPipes 将所需的数据从第一个程序发送到第二个程序。当第二个程序关闭时,我需要将一些数据发送回第一个程序。我在第一个程序中设置了 NamedPipeServerStream,并从第二个程序的 Closing 事件中设置了 NamedPipeClientStream。现在,当我尝试从 ClientStream 写入时,我得到了一个损坏的管道错误。

这是第一个程序的代码:

private void CreateOverlay(object sender, EventArgs e)
    {
        if (oinstallfolder != null)
        {
            string processfilename = oinstallfolder.ToString() + "\\SecondProgram.exe";*/

        string processfilename = "SecondProgram.exe";

        if (File.Exists(processfilename))
            {

                foreach (Process clsProcess in Process.GetProcesses())
                {
                    if (clsProcess.ProcessName.Equals("SecondProgram"))
                    {
                        this.threadHandleOverlayBounds = new Thread(new ThreadStart(this.ExchangeMapOverlayBoundsServer));
                        this.threadHandleOverlayBounds.Start();
                        this.threadHandleOverlayFile = new Thread(new ThreadStart(this.ExchangeMapOverlayFileServer));
                        this.threadHandleOverlayFile.Start();
                        ShowWindow(clsProcess.MainWindowHandle, SW_SHOWNORMAL);
                        SetForegroundWindow(clsProcess.MainWindowHandle);
                        return;
                    }
                }
            try
            {
                this.threadHandleOverlayBounds = new Thread(new ThreadStart(this.ExchangeMapOverlayBoundsServer));
                this.threadHandleOverlayBounds.Start();
                Logger.Logger.Write("Log.txt", "Starting Filethread serverside");

                this.threadHandleOverlayFile = new Thread(new ThreadStart(this.ExchangeMapOverlayFileServer));
                this.threadHandleOverlayFile.Start();

                Process.Start(processfilename);
            }
            catch { }

            }
        }
    }


 private void ExchangeMapOverlayFileServer()
        {
            try
            {
                using (NamedPipeServerStream namedPipeServer = new NamedPipeServerStream("OverlayFilePipe", PipeDirection.In, 1, PipeTransmissionMode.Byte))
                {
                    string line;
                    namedPipeServer.WaitForConnection();
                    StreamReader sr = new StreamReader(namedPipeServer);
                    line = sr.ReadLine();
                    namedPipeServer.Disconnect();
                    namedPipeServer.Close();
                }
            }
            catch(Exception e)
            {
                Logger.Logger.Write("OverlayGenerator.txt", "namedPipeServer exception: " + e.Message + "\n" + e.StackTrace);
            }

        }

这是第二个程序的代码

this.Closing += (s, a) =>
        {
            Logger.Logger.Write("Log.txt", "Window Closing");
            this.threadHandleOverlayFile = new Thread(new ThreadStart(this.HandleWindowClosing));
            this.threadHandleOverlayFile.Start();
            while (!done)
            {
                Thread.Sleep(100);
            }

        };


  private void HandleWindowClosing()
    {
        if (!String.IsNullOrEmpty(this.latestSavedOverlayPath))
        {
            try
            {
                using (NamedPipeClientStream namedPipeClient = new NamedPipeClientStream(".", "OverlayFilePipe", PipeDirection.Out))
                {
                    namedPipeClient.Connect();
                    StreamWriter sw = new StreamWriter(namedPipeClient);
                    sw.AutoFlush = true;
                    sw.WriteLine("testphrase");
                    namedPipeClient.Close();
                    this.done = true;
                }

            }
            catch (Exception e) { Logger.Logger.Write("OverlayGenerator.txt", "Exception in Client: " + e.Message + "\n" + e.StackTrace); }
        }
        else
        {
            Logger.Logger.Write("OverlayGenerator.txt", "Latest saved OverlayPath = " + this.latestSavedOverlayPath);
        }
    }

我尝试了 Autoflush=true 和没有。有了它,我在生产线上遇到了一个破损的管道异常

sw.WriteLine("testphrase");

没有它,客户端只会运行到最后,什么也没有发生。

我的错误在哪里?谢谢你。

编辑

好吧,我就是不明白。我制作了一个测试程序,它的构建方式与实际程序相同。两个应用程序,第一个启动第二个。我在第一个应用程序的一个线程中启动管道服务器,在第二个应用程序中启动客户端,也在一个线程中。唯一的区别是,我在调试模式下运行这个测试项目,而我不能对实际程序执行此操作。现在,在测试程序中,这件事真的很简单,并且有效。当我在实际程序中使用完全相同的方法时,它不起作用。在测试程序中,我需要在 streamwriter 上使用 flush 并且我没有遇到异常。线程的同步由管道本身处理,如果我理解正确的话应该是这样。

大师长这样:

private const string CLIENTPROC = "C:\\Users\\Maik\\Source\\Repos\\PipeTest\\PipeClient\\obj\\x86\\Release\\PipeClient.exe";
        private ManualResetEvent threadResetEvent;
        private Thread threadHandlePipeSendLast;
        private Process procClient;
        private string msgPipeSend;
        private volatile bool bMsgPipeSend;
        public MainWindow()
        {
            InitializeComponent();
            this.threadResetEvent = new ManualResetEvent(false);
            System.Diagnostics.Debug.WriteLine("### starting thread");
            this.threadHandlePipeSendLast = new Thread(new ThreadStart(this.ExchangeMapOverlayFileServer));
            this.threadHandlePipeSendLast.Start();
        }

        private void ExchangeMapOverlayFileServer()
        {
            System.Diagnostics.Debug.WriteLine("server thread started");
            Thread.CurrentThread.Name = "apocalypse";
            try
            {
                using (NamedPipeServerStream namedPipeServer = new NamedPipeServerStream("ClosingPipe", PipeDirection.In, 1, PipeTransmissionMode.Byte))
                {
                    string line;

                    namedPipeServer.WaitForConnection();
                    StreamReader sr = new StreamReader(namedPipeServer);
                    Thread.Sleep(100);
                    line = sr.ReadLine();
                    handleRecvMsgFromPipe(line);
                    namedPipeServer.Disconnect();
                    namedPipeServer.Close();
                }
            }
            catch (Exception e)
            {
                System.Diagnostics.Debug.WriteLine("### " + e.Message + "\n" + e.StackTrace);
            }
        }

        private void handleRecvMsgFromPipe(string line)
        {
            this.outbox.Text = line;
        }

        private void buttonOpenFormClient_Click(object sender, EventArgs e)
        {
#if DEBUG

#else
            if (this.procClient == null)
            {
                try
                {
                    this.procClient = Process.Start(new ProcessStartInfo(CLIENTPROC));
                }
                catch (Exception exc)
                {
                    MessageBox.Show(exc.Message, "Error");
                }
            }
#endif
        }
    }

这就是客户端:

private ManualResetEvent threadResetEvent;
        private Thread threadHandlePipeSendLast;

        private string msgPipeSend;
        private volatile bool bMsgPipeSend;
        private bool done;

        public MainWindow()
        {
            InitializeComponent();
            this.threadResetEvent = new ManualResetEvent(false);
            this.Closing += (s, a) =>
            {
                System.Diagnostics.Debug.WriteLine("+++ FormClosing started.");
                this.threadHandlePipeSendLast = new Thread(new ThreadStart(this.HandleWindowClosing));
                this.threadHandlePipeSendLast.Start();
                while (!done)
                {
                    Thread.Sleep(1000);
                }
            };
        }

        private void HandleWindowClosing()
        {
            try
            {
                using (NamedPipeClientStream namedPipeClient = new NamedPipeClientStream(".", "ClosingPipe", PipeDirection.Out))
                {
                    namedPipeClient.Connect();
                    StreamWriter sw = new StreamWriter(namedPipeClient);
                    //sw.AutoFlush = true;
                    sw.WriteLine("last message");
                    namedPipeClient.WaitForPipeDrain();
                    namedPipeClient.Close();
                    this.done = true;
                }

            }
            catch (Exception e) { System.Diagnostics.Debug.WriteLine(e.Message + "\n" + e.StackTrace); }
        }

谁能告诉我,为什么这适用于测试应用程序而不是实际应用程序?我还尝试了从 Thread.Sleep(x) 在程序中的不同点通过 Thread.Join() 到像 WaitForPipeDrain 之类的管道方法(只是被忽略)的各种事情。

标签: c#named-pipesbroken-pipe

解决方案


推荐阅读