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

时间:2010-12-20 12:26:38

标签: c# named-pipes

我有一个托管自定义用户控件的Windows窗体。此用户控件将启动一个单独的进程(.exe),用于创建和初始化NamedPipeServerStream。一旦进程初始化NamedPipeServerStream,用户控件就会以NamedPipeClientStream的身份连接到它。

一切正常。

在Windows窗体上,我有一个名为“检查更新”的按钮。按下此按钮时,NamedPipeClientStream会向服务器发送一条消息,服务器响应该消息,其中一条消息框说“我已被告知要检查更新”。所以我可以告诉这个客户>服务器通信工作正常。

这是问题所在。然后服务器应该向客户端发送消息BACK,告诉它现在正在检查更新(因此用户控制可以在服务器收到命令后更新其状态)。但是每当发生这种情况时,一切都会锁定。

现在我假设这是因为我试图同时读取和写入命名管道?

以下是服务器和客户端的一些代码段。 (这两个片段在各自的进程中以单独的线程运行,以便不阻止UI)

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(命名管道客户端):

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

以下代码段是负责从每个组件写入客户端/服务器的方法。 (唯一的区别在于名称,即SendMessageToClientSendMessageToServer

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

isWritingToPipe变量是一个简单的bool,当相应进程尝试写入命名管道时,该变量为true。这是我最初尝试解决问题的方法。

非常感谢任何帮助!

3 个答案:

答案 0 :(得分:1)

System.IO.Pipes.PipeStream有一个方法WaitForPipeDrain(),这是在交换消息时管理客户端和服务器之间协调的正确方法。

管道的TransmissionMode也可能会影响一些事情:您使用的是字节模式还是消息模式?例如,我不确定StreamReader中的流包装如何与管道消息模式语义一起播放。有关消息模式的更多信息,请参阅this SO answer

答案 1 :(得分:0)

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

中执行此操作

答案 2 :(得分:0)

解决这个问题的方法是重新考虑软件的设计。

UserControl不是让UserControl在更新过程的每一步都与单独的应用程序对话,而是自己处理它,然后最终需要应用更新时(这涉及覆盖应用程序文件,因此需要单独使用)首先,它只是使用Process.Start(“...”)和一些命令行参数调用一个单独的进程来完成工作。

比尝试为此任务执行进程间通信更简单的解决方案。

尽管如此,我还是很高兴找出为什么我的双向通信无效。