プロセス間通信とは何か
その名の通り、プロセス間で通信をすることです。
特に今回は、あるプロセスとその子プロセスの間で通信することを目指します。
きっかけ
(この章は読み飛ばしていただいて構いません)
プロセス間通信をやってみたいと思ったきっかけを述べておきます。
きっかけは、将棋AIを触ったことでした。
将棋AIは最近のAIブームの先駆け的なもので、先端的な技術として前々から興味を持っていました。
通常はshogiGUIなどのGUIにエンジンを登録して使うのですが、エンジンを直に使うこともできます。エンジンの本体であるexeを実行するとターミナルが立ち上がるので、以下のように入力します。
isready
position sfen ~~~
go infinite
stop
※sfenというのは将棋の局面を表す形式の一つです。
すると、現局面の評価値と次の推奨手が出てきます。
これは標準入出力を利用しているのですが、上のような入力作業を自動化できないか?と考えたときに出た手段がプロセス間通信でした。
プロセス間通信とは
プロセスは親子関係を持っています。親子プロセス間の通信を標準入出力を通じて行える仕組みがあります。
まだ中身の仕組み(どういうシステムコールを発行しているのかなど)ははっきり理解できていないので割愛します。
同期通信と非同期通信
同期通信
ではまず、同期通信の処理の書き方から紹介します。
.NETのprocessクラスで実装します。
$p = New-Object System.Diagnostics.Process
$p.StartInfo.FileName = "path/to/hoge.exe"
$p.StartInfo.WorkingDirectory = "path/to"
$p.StartInfo.RedirectStandardInput = $true
$p.StartInfo.RedirectStandardOutput = $true
$p.StartInfo.UseShellExecute = $false
$p.StartInfo.CreateNoWindow = $true
$p.Start()
$p.StandardInput.WriteLine("hello")
$p.StandardInput.Flush()
$response = $p.StandardOutput.ReadLine()
Write-Host "child says: $response"
最初のフラグの設定は適当にやります。
WriteLineすると入力して、flushで送信します。
出力はバッファにたまっていて、ReadLineすると最初の一行を読み出します。
何行か返した後最後にendを返したら終わり、というような場合は下記のように書けば制御できます。
while($true){
$response = $p.StandardOutput.ReadLine()
Write-Host "child says: $response"
if($response -eq "end"){break}
}
非同期通信
ObjectEventを使います。
$p = New-Object System.Diagnostics.Process
$p.StartInfo.FileName = "path/to/hoge.exe"
$p.StartInfo.WorkingDirectory = "path/to" # プロセスを立ち上げる時に渡すパス
$p.StartInfo.RedirectStandardInput = $true
$p.StartInfo.RedirectStandardOutput = $true
$p.StartInfo.UseShellExecute = $false
$p.StartInfo.CreateNoWindow = $true
Register-ObjectEvent $p 'OutputDataReceived' -Action {
Write-Host "OUT: $($EventArgs.Data)"
}
$p.Start()
$p.BeginOutputReadLine()
$p.StandardInput.WriteLine("hello")
Start-Sleep 5
$p.StandardInput.WriteLine("quit")
こちらの方が若干ロジックを組むのが難しい気がします。詳しいことは分かっていません。
わかっていないこと
- どういうシステムコールを発行しているか。どういう仕組みか。
最後までお読みいただきありがとうございました。