Как правильно использовать Mono.Unix.UnixPipes.CreatePipes? - PullRequest
1 голос
/ 16 января 2012

Я хочу общаться с подпроцессом, используя канал, отличный от 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$ 

Этот пример был скомпилирован и запущен с Mono 2.10, как и в Ubuntu Oneiric.

Что я делаю не так?Как я могу гарантировать, что дочерний процесс сможет писать в канал?


EDIT - похоже, 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 голосов
/ 16 января 2012

Насколько я понимаю, здесь нельзя использовать трубу в двух направлениях. Другими словами, вы не можете читать и писать с одним и тем же каналом. Вам нужно два.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...