callmekohei's blog

callmekoheiのひとりごと

F#で簡単プロセス間通信

Summary

親子プロセスでの通信

こんな感じ

$ mono abc.exe 
HELLO from child process
hello --- from child process --- 
apple
apple --- from child process --- 
banana
banana --- from child process --- 
cherry
cherry --- from child process --- 
quit

$ 

子プロセス

文字を入力するとabc --- from child process ---と返す

let rec main s =
    match s with
    | "quit" -> ()
    | "init" -> stdout.WriteLine("HELLO from child process")
                main ( stdin.ReadLine() )
    | _      -> stdout.WriteLine( s + " --- from child process --- " )
                main ( stdin.ReadLine() )

[<EntryPointAttribute>]
let entry arg =
    main "init"
    0

親プロセス

親プロセスで文字を入力

→ 子プロセスに文字を送る

→ 子プロセスの標準出力が出力されたら取得する(イベントで見張ってる)

open System.Diagnostics

type Interaction (fp:string, args:string, wd:string) =
    
    // 子プロセスの起動パラメータを作成する
    let procStartInfo =
        ProcessStartInfo(
            FileName               = fp   ,
            Arguments              = args ,
            WorkingDirectory       = wd   ,
            RedirectStandardInput  = true , // 子プロセスの標準入力をリダイレクトする
            RedirectStandardOutput = true , // 子プロセスの標準出力をリダイレクトする
            RedirectStandardError  = true , // 子プロセスの標準エラーをリダイレクトする
            UseShellExecute        = false  // シェルを使用せず子プロセスを起動する(リダイレクトするために必要)
    )
    
    // 子プロセスをインスタンス化
    let ps = new Process(StartInfo = procStartInfo)

    // Set our event handler to asynchronously read the ps output.
    // リダイレクトした標準出力の内容を受信するイベントハンドラを設定する
    do ps.OutputDataReceived
       |> Event.add ( fun (args :DataReceivedEventArgs) ->
           stdout.WriteLine(args.Data) |> ignore )
    
    // 子プロセスを起動する
    do ps.Start() |> ignore
    // 子プロセスがアイドル状態になるまで無期限に待機
    do ps.WaitForInputIdle() |>ignore
    // Start the asynchronous read of the ps output stream.
    // 標準出力の非同期読み込みを開始する
    do ps.BeginOutputReadLine()

    // リダイレクトした子プロセスの標準入力にテキストを書き込む
    member this.Send(message:string) = ps.StandardInput.WriteLine(message)
    
    // 子プロセスを終了する
    member this.Quit() = ps.Kill()



let mono    = "/usr/local/Cellar/mono/4.8.1.0/bin/mono"
let args    = "/Users/kohei/Documents/childProcess.exe"
let workdir = "/Users/kohei/Documents/"
let replyer = Interaction(mono,args,workdir)

let rec main s =
    match s with
    | "quit" -> replyer.Quit()
    | _      -> replyer.Send(s)
                main ( stdin.ReadLine() )

[<EntryPointAttribute>]
let entry arg =
    main "hello"
    0