简体   繁体   English

如何在C#中异步读取/写入命名管道

[英]How To Asynchronously Read/Write A Named Pipe In C#

I have a Windows form which hosts a custom User Control. 我有一个托管自定义用户控件的Windows窗体。 This User Control fires up a seperate process (a .exe) which creates and initializes a NamedPipeServerStream. 此用户控件启动一个单独的进程(.exe),该进程创建并初始化NamedPipeServerStream。 Once the process initializes the NamedPipeServerStream, the User Control connects to it as a NamedPipeClientStream. 一旦进程初始化了NamedPipeServerStream,用户控件便作为NamedPipeClientStream连接到它。

This all works fine. 这一切都很好。

On the Windows form I then have a button called "Check For Updates". 然后,在Windows窗体上,我有一个名为“检查更新”的按钮。 When this button is pressed, the NamedPipeClientStream sends a message to the server, to which the server responds which a MessageBox saying "I've been told to check for updates". 当按下此按钮时,NamedPipeClientStream向服务器发送一条消息,服务器响应该消息,并在消息框中显示“已通知我检查更新”。 So I can tell this client > server communication is working fine. 因此,我可以告诉此客户端>服务器通信正常。

Here's the problem. 这是问题所在。 The server is then supposed to send a message BACK to the client telling it that it's now checking for updates (So the User Control can update its status after verying its command was received by the server). 然后,服务器应该向客户端发送一条消息BACK,告诉它现在正在检查更新(因此,用户控件可以在服务器接收到命令后更新其状态)。 But whenever this happens, everything locks up. 但是,只要发生这种情况,一切都会锁定。

Now I am going to assume that this is because I am attempting to both read AND write to the Named Pipe at the same time? 现在,我假设这是因为我试图同时读取和写入命名管道?

Below are some code snippets from both the Server and the Client. 以下是来自服务器和客户端的一些代码片段。 (Both these snippets run in seperate threads in their respective processes so as to not block the UI) (这两个代码段均在各自的进程中运行在单独的线程中,以免阻塞UI)

GUpdater (The Named Pipe Server): GUpdater(命名管道服务器):

private void WaitForClientCommands()
{
    // Wait for a connection from a Named Pipe Client (The GUpControl)
    pipeStream.WaitForConnection();
    pipeConnected = true;

    // Create a StreamWriter/StreamReader so we can write/read to the Named Pipe
    pipeStreamWriter = new StreamWriter(pipeStream) { AutoFlush = true };
    pipeStreamReader = new StreamReader(pipeStream);

    // Now that we have a connection, start reading in messages and processing them
    while (true)
    {
        // Skip this time if we are currently writing to the pipe
        if(isWritingToPipe) continue;

        var message = pipeStreamReader.ReadLine();
        if (message == null)
        {
            // We don't want to hog up all the CPU time, so if no message was reaceived this time, wait for half a second
            Thread.Sleep(500);
            continue;
        }

        switch(message)
        {
            case "CheckForUpdates":
                //MessageBox.Show("Told to check for updates");
                SendMessageToClient("Checking For Updates, Woot!");
                break;
            case "DownloadUpdate":
                MessageBox.Show("Told to download update");
                break;
            case "ApplyUpdate":
                MessageBox.Show("Told to apply update");
                break;
        }
    }
}

GUpControl (The Named Pipe Client): GUpControl(命名管道客户端):

private void WaitForServerCommands()
{
    if(!pipeConnected) return;

    // Now that we have a connection, start reading in messages and processing them
    while (true)
    {
        // Skip this time if we are currently writing to the pipe
        if (isWritingToPipe) continue;

        // Attempt to read a line from the pipe
        var message = pipeStreamReader.ReadLine();
        if (message == null)
        {
            // We don't want to hog up all the CPU time, so if no message was reaceived this time, wait for half a second
            Thread.Sleep(500);
            continue;
        }

        MessageBox.Show("I got a message from the server!!\r\n" + message);
    }
}

The following snippet is the method that is responsible for writing to the Client/Server from each component. 以下代码段是负责从每个组件写入客户端/服务器的方法。 (The only difference is in the name, ie SendMessageToClient and SendMessageToServer ) (唯一的区别是名称,即SendMessageToClientSendMessageToServer

private void SendMessageToServer(string message)
{
    if(pipeConnected)
    {
        isWritingToPipe = true;
        pipeStreamWriter.WriteLine(message);
        isWritingToPipe = false;
    }
}

The isWritingToPipe variable is a simple bool that is true when the respective process is attempting to write to the Named Pipe. isWritingToPipe变量是一个简单的布尔值,当相应的进程试图写入命名管道时为true。 This was my initial attempt at solving the problem. 这是我最初解决问题的尝试。

Any help is much appreciated! 任何帮助深表感谢!

System.IO.Pipes.PipeStream has a method WaitForPipeDrain() which is the correct way to manage coordination between the client and server when exchanging messages. System.IO.Pipes.PipeStream具有方法WaitForPipeDrain() ,这是交换消息时管理客户端和服务器之间协调的正确方法。

The TransmissionMode for the pipe may also be affecting things: are you using Byte mode or Message mode? 管道的TransmissionMode可能还会影响事物:您使用的是字节模式还是消息模式? I'm not sure how well wrapping the stream in a StreamReader plays with the pipe message mode semantics, for example. 例如,我不确定将流包装在StreamReader中与管道消息模式语义之间的关系如何。 See this SO answer for more on message mode. 有关消息模式的更多信息,请参见此SO答案

当您向服务器发送信号以检查更新时,请在BackgroundWorker类中进行操作

The solution to this problem turned out to be a matter of rethinking the design of the software. 事实证明,解决该问题的方法是重新考虑软件的设计。

Instead of having a UserControl that talks to a seperate application each step of the Update process, the UserControl handles it all itself and then finally when it needs to apply the update (which involves overwriting application files, hence the need for a seperate process in the first place) it simply uses Process.Start("...") along with some command line arguements to call a seperate process to finish the job. 而不是让UserControl在更新过程的每个步骤中与单独的应用程序对话,而是由UserControl自己处理所有操作,然后最终在需要应用更新时进行处理(这涉及覆盖应用程序文件,因此需要在应用程序中进行单独的处理)首先),它仅使用Process.Start(“ ...”)以及一些命令行参数来调用单独的进程以完成工作。

A much simpler solution than trying to do Inter-Process Communication for this task. 比尝试为此任务进行进程间通信要简单得多的解决方案。

Still, it would have been nice to find out why my Bi-Directional communication wasn't working. 仍然很高兴找出为什么我的双向通讯不起作用。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM