使用命名管道模拟流程替换

时间:2018-02-28 23:04:37

标签: c# winapi named-pipes

我正在尝试在.NET中启动子进程并将其输出重定向到命名管道。尝试写入子进程中的stdout应该阻塞,直到客户端实际读取命名管道。

这是我的代码:

using System;
using System.Diagnostics;
using System.IO.Pipes;

namespace psub
{
    class Program
    {
        static void Main(string[] args)
        {
            var pipeName = "testpipe"; // Guid.NewGuid().ToString();
            Console.WriteLine($@"\\.\pipe\{pipeName}");

            var psi = new ProcessStartInfo()
            {
                FileName = "ping",
                Arguments = "google.com",

                UseShellExecute = false,
                RedirectStandardOutput = true
            };

            using (var pipeServer = new NamedPipeServerStream(pipeName, PipeDirection.Out))
            using (var process = new Process { StartInfo = psi })
            {
                pipeServer.WaitForConnection();
                process.Start();
                process.StandardOutput.BaseStream.CopyTo(pipeServer);
                process.WaitForExit();
            }
        }
    }
}

当我启动此可执行文件时,它会按预期在pipeServer.WaitForConnection();处阻止。然后我打开cmd.exe并运行type \\.\pipe\testpipe,尝试从命名管道[1]中读取。

这会导致以下错误(在cmd会话中):

All pipe instances are busy.

此外,在C#程序中,pipeServer.WaitForConnection完成,执行进行到...CopyTo(pipeServer),其爆炸为:

Unhandled Exception: System.IO.IOException: Pipe is broken.

我不明白为什么会发生All pipe instances are busy.错误。

根据我的理解,有一个服务器(在C#程序中实例化)将写入命名管道。一旦执行到CopyTo,数据将被传送到程序的单个被阻塞线程上的命名管道服务器。

还有一个命名的管道客户端(type \\.\pipe\testpipe进程),它将减轻服务器尝试写入的数据的命名管道。

那么为什么会出现“所有管道实例都忙”错误?

我已经尝试将new NamedPipeServerStream(pipeName, PipeDirection.Out)调整为new NamedPipeServerStream(pipeName, PipeDirection.Out, 2)以及其他调整,但没有真正了解问题是什么或如何解决问题。有人可以像我五岁那样解释一下吗?

[1]:目标是模拟UNIX shell中可用的process substitution功能,因此我必须能够从\\.\pipe\<some file name>读取,而不是使用C ++或.NET来实例化管道的客户。

2 个答案:

答案 0 :(得分:2)

在cmd中使用type <some_file_name>时,首先为此GetFileAttributes

致电<some_file_name>

enter image description here

GetFileAttributes内部(内部内核)临时打开文件,用于查询它的属性(实际上 - 需要查询文件系统设备以及发送查询请求 - 需要打开文件)。

对于命名管道文件,这会产生致命的副作用 - 服务器端连接(打开文件)并且只是断开连接(关闭时)。

仅在此cmd(再次)打开文件

之后

enter image description here

但您的管道服务器已经没有监听(断开连接后)。结果cmd通常收到STATUS_PIPE_NOT_AVAILABLE错误 - 在侦听状态下找不到命名管道的实例。 - 它转换为win32错误ERROR_PIPE_BUSY - 所有管道实例正忙着

作为单独的注释 - 3种不同的状态错误:

STATUS_INSTANCE_NOT_AVAILABLE已达到最大命名管道实例数。

STATUS_PIPE_NOT_AVAILABLE在侦听状态下无法找到命名管道的实例。

STATUS_PIPE_BUSY转换为相同的单个win32错误ERROR_PIPE_BUSY。但在您的情况下,原始错误恰好是STATUS_PIPE_NOT_AVAILABLE

结论 - cmd type命令不设计与管道交互。或者您需要创建最小2个管道在同一管道名称上的结束方式。

答案 1 :(得分:-2)

您无法通过Windows命名管道的命令行界面进行访问。有关详细信息,请参阅http://en.wikipedia.org/wiki/Named_pipe