2012-01-16 4 views
1

Я хочу общаться с подпроцессом, используя другой канал, отличный от stdin, stdout и stderr. Я пытаюсь использовать Mono.Unix.UnixPipes.CreatePipes для этого. Тем не менее, я не могу найти никаких примеров, и мое лучшее предположение о том, как его использовать, не работает. Кажется, что дочерний процесс, который я создаю с помощью Process.Start, не может записываться в унаследованный дескриптор файла. Мне интересно, возможно, это вообще не унаследовало ручку. Вот мой (пониженная) код:Как правильно использовать Mono.Unix.UnixPipes.CreatePipes?

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

Вот результат, когда он работает:

[email protected]:~/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. 
[email protected]:~/dev$ 

Этот пример был скомпилирован и работать с Mono 2.10, как распределены в Ubuntu Грез.

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


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. Есть ли другой способ?

+0

Это зависит от того, чего вы пытаетесь достичь. Process.Start не дает вам гарантии, что вновь созданный процесс будет дочерним процессом, и даже если понятие дочернего процесса вообще существует, оно должно быть перекрестной платформой. Вы можете создавать поток и общаться с использованием неназванного канала, но это то, что вам нужно? –

ответ

0

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

+0

Не думаю, что я использую трубу в двух направлениях. CreatePipes создает два дескриптора файлов, один называется Reading, а один называется Writing. Родительский процесс читает из Рединга, а дочерний процесс записывает в Writing. – Weeble

Смежные вопросы