我怎样才能正确使用Mono.Unix.UnixPipes.CreatePipes?

时间:2012-01-16 12:03:50

标签: c# mono

我想使用除stdin,stdout和stderr之外的管道与子进程通信。我正在尝试使用Mono.Unix.UnixPipes.CreatePipes。但是,我找不到任何示例,我最好的猜测如何使用它是行不通的。看来我用Process.Start创建的子进程无法写入继承的文件句柄。我想知道是否它实际上还没有真正继承句柄。这是我的(简化)代码:

using System;
using System.Diagnostics;
using System.IO;
using System.IO.Pipes;
using System.Threading;
using System.Collections.Generic;
using Mono.Unix;

class Program
{
    static void Main(string[] args)
    {
        if (args.Length==0)
        {
            InvokeChildProcess(args);
        }
        else
        {
            RunAsChildProcess(args);
        }
    }
    static int InvokeChildProcess(string[] aArgs)
    {
        var childToParentPipe = Mono.Unix.UnixPipes.CreatePipes();
        var childToParentStream = childToParentPipe.Reading;
        string childHandle = childToParentPipe.Writing.Handle.ToString();
        var startInfo = new ProcessStartInfo(
            System.Reflection.Assembly.GetExecutingAssembly().Location,
            childHandle)
            {
                UseShellExecute = false,
            };
        Process childProcess = Process.Start(startInfo);
        childToParentPipe.Writing.Close();
        using (var reader = new StreamReader(childToParentStream))
        {
            Console.WriteLine("[PARENT] Waiting for child output...");
            string output = reader.ReadToEnd();
            Console.Write("[PARENT] Received output ({0} chars): ", output.Length);
            Console.WriteLine(output);
            Console.WriteLine("[PARENT] Waiting for child to exit...");
            childProcess.WaitForExit();
            Console.WriteLine("[PARENT] Saw child exit with code {0}.", childProcess.ExitCode);
            return childProcess.ExitCode;
        }
    }
    static void RunAsChildProcess(string[] args)
    {
        int handle=int.Parse(args[0]);
        Console.WriteLine("[CHILD] Writing to file handle {0}.", handle);
        var pipeToParent = new Mono.Unix.UnixStream(handle);
        Thread.Sleep(2000);
        using (var writer = new StreamWriter(pipeToParent))
        {
            writer.WriteLine("Message from child.");
            writer.Flush();
            Environment.Exit(123);
        }
    }
}

这是运行时的输出:

weeble@weeble-vm-oneiric32:~/dev$ mono MinimalPipeTest.exe
[PARENT] Waiting for child output...
[PARENT] Received output (0 chars): 
[PARENT] Waiting for child to exit...
[CHILD] Writing to file handle 4.

Unhandled Exception: System.ArgumentException: Can not write to stream
  at System.IO.StreamWriter..ctor (System.IO.Stream stream, System.Text.Encoding encoding, Int32 bufferSize) [0x00000] in <filename unknown>:0 
  at System.IO.StreamWriter..ctor (System.IO.Stream stream) [0x00000] in <filename unknown>:0 
  at (wrapper remoting-invoke-with-check) System.IO.StreamWriter:.ctor (System.IO.Stream)
  at Program.RunAsChildProcess (System.String[] args) [0x00000] in <filename unknown>:0 
  at Program.Main (System.String[] args) [0x00000] in <filename unknown>:0 
[ERROR] FATAL UNHANDLED EXCEPTION: System.ArgumentException: Can not write to stream
  at System.IO.StreamWriter..ctor (System.IO.Stream stream, System.Text.Encoding encoding, Int32 bufferSize) [0x00000] in <filename unknown>:0 
  at System.IO.StreamWriter..ctor (System.IO.Stream stream) [0x00000] in <filename unknown>:0 
  at (wrapper remoting-invoke-with-check) System.IO.StreamWriter:.ctor (System.IO.Stream)
  at Program.RunAsChildProcess (System.String[] args) [0x00000] in <filename unknown>:0 
  at Program.Main (System.String[] args) [0x00000] in <filename unknown>:0 
[PARENT] Saw child exit with code 1.
weeble@weeble-vm-oneiric32:~/dev$ 

此示例是使用在Ubuntu Oneiric中分发的Mono 2.10编译和运行的。

我做错了什么?如何确保子进程能够写入管道?


编辑 - 看起来Process.Start确实关闭了子进程中除0,1和2之外的所有文件描述符。请参阅CreateProcess中的这些:

https://github.com/mono/mono/blob/master/mono/io-layer/processes.c#L988

for (i = getdtablesize () - 1; i > 2; i--) {
    close (i);
}

我想这意味着我不能使用UnixPipes和Process.Start。还有另一种方式吗?

1 个答案:

答案 0 :(得分:0)

据我所知,你不能在这里双向使用管道。换句话说,您无法使用相同的管道进行读写。你需要两个。