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

问题描述 投票:0回答:2

我正在尝试在.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来实例化管道的客户端。

c# winapi named-pipes
2个回答
2
投票

当你在cmd中使用type <some_file_name>时 - 它首先为GetFileAttributes调用<some_file_name>

enter image description here

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

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

只有在此命令(再次)打开文件后

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个管道在同一管道名称上的结尾。


-2
投票

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

© www.soinside.com 2019 - 2024. All rights reserved.