プロセス間通信(IPC)
別プロセスとデータや合図をやり取りする仕組みの総称。
名前付きパイプ
Windowsのプロセス間通信手段のひとつ。リモートからの利用はアプリ自身のポートではなくSMB(TCP 445)を経由する。
同一マシン内の要求応答通信
コマンドを送って結果を受け取る、同一マシン内で完結する対話的な通信の形態。
ローカルTCP
localhostに対するTCP接続によるプロセス間通信で、言語・ランタイム・OSをまたいで通信できる汎用的なIPC手段。
localhostへのTCP接続
マシンをまたぐ通信の必要性
同一マシン内に閉じず、別マシンや別OSのプロセスとも通信できる必要がある要件。
gRPC
HTTP/2ベースの高性能なRPCフレームワーク。WCFサーバーのmodern化先の1つ。
フレーミング(メッセージ境界の決定)
バイトの並びのどこからどこまでが1メッセージかを決める仕組み。TCPでは自前設計が必須になる。
サービス・メッセージ増加による自前プロトコル維持負担
サービスやメッセージの種類が増え、自前プロトコルのswitch文とドキュメントの維持が負担になってきた状態。
小規模なツール間通信(コマンド数個)
コマンドが2〜3種類しかない程度の、小規模なツール間の通信。
ファイルマッピング(メモリマップトファイル)
ファイルの内容をプロセスやシステムのアドレス空間にマップする仕組み。ディスク上のファイルに裏打ちされる形と、CreateFileMappingにINVALID_HANDLE_VALUEを渡してページファイルに裏打ちされる形(名前付き共有メモリ)がある。Windowsのキャッシュマネージャー自身の実装基盤でもある。
メモリマップトファイル
大容量・高頻度データ転送
画像フレームや波形データのように、大きくて頻繁に転送されるデータのやり取り。
制御面とデータ面の分離(2チャネル構成)
開始・停止・設定変更などの制御メッセージと、実データの転送とで別のIPCチャネルを使い分ける設計。
COM(コンポーネントオブジェクトモデル)
公開インターフェース、レジストリ登録、Apartment Modelなどを土台にした、Windowsのバイナリ互換コンポーネントモデル。
32bit/64bitブリッジ
32bitプロセスから64bit専用のDLLやSDKの機能を、別プロセスに切り出して呼び出す構成。
PipeSecurity(名前付きパイプのACL)
名前付きパイプへの接続を許可するアカウント・グループを明示的に設定する.NETのアクセス制御機構。
パイプ名の占有(スクワッティング)
悪意あるプロセスが先に同じ名前で名前付きパイプのサーバーを立てて待ち受け、クライアントの接続を奪う攻撃。
ファイル連携
一方のプロセスが出力フォルダーにファイルを置き、もう一方が拾って処理する疎結合な連携方式。
ファイルベースの連携
疎結合・非同期のバッチ連携
双方が同時に起動している必要がなく、証跡を残しながら非同期に処理を受け渡す連携形態。
Windowsサービス
ユーザーのサインインと無関係にバックグラウンドで動くWindowsのプロセス。
サービス
同一マシン内の要求応答(コマンドを送って結果をもらう)通信では名前付きパイプが第一候補として推奨される
将来ネットワークを越える可能性が見えているなら最初からローカルTCPかgRPCにする
マシン越えや言語混在が見えている構成ではgRPCも有力な選択肢として推奨される
TCPはバイトストリームで送った単位で届く保証がないため、length プレフィックスなどのフレーミングをアプリ層で設計する必要がある
.NET 8以降のASP.NET Core(Kestrel)でWindows上のプロセス間通信に使う場合に限り、gRPCの通信路として名前付きパイプを直接サポートし、ポートレスでACL統合された構成を作れる。gRPCの通信路は通常TCP(HTTP/2)である
サービスや呼び出しの種類が増え自前プロトコルのswitch文とドキュメント維持が負担になってきたらgRPCの枠組みが効く
コマンド数が少ないツール間通信では名前付きパイプ+JSONのほうが総コストが低い
コマンドが2〜3種類しかないツール同士にはASP.NET Coreのホスティング基盤を抱えるgRPCはオーバーキルになりがちである
画像フレームや波形データのような大容量・高頻度のデータには共有メモリ(メモリマップトファイル)が最速で、この用途にはほぼ一択と言える
共有メモリは同期を1バイトも提供しないため、開始・停止・設定変更のような制御メッセージのやり取りにも使おうとする場合は、制御面を名前付きパイプなど別チャネルに逃がし、データ面だけを共有メモリに乗せる構成が定石とされる
Windows上でこのパターンを組む場合、制御面(開始・停止・設定変更)は名前付きパイプなど低頻度の要求応答チャネルに割り当てる
Windows上でこのパターンを組む場合、データ面(フレーム・波形などの高頻度データ)は共有メモリ(メモリマップトファイル)に割り当てる
32bitアプリから64bitのDLLを使うような境界越えでは、COM基盤がマーシャリングを肩代わりするアウトプロセスCOMサーバーが今も実用的な選択肢である
呼び出し側がC#同士の32/64bitブリッジでは、64bitのヘルパープロセスを名前付きパイプで呼ぶ構成のほうが配布も調査も楽である
COM(アウトプロセス)は新規のアプリ間通信の第一候補にはもうしないが、VBA連携や32/64bitブリッジの文脈では今も現役の道具として温存される
権限境界を越える通信(UACブローカーやサービスとの通信)では既定のCurrentUserOnlyが使えないため、PipeSecurityでACLを明示的に構成する
パイプ名は\\.\pipe\配下の全員から見える名前空間にあり、悪意あるプロセスが同名で先にサーバーを立てて待ち受けるスクワッティングが起こり得る
サーバー側でPipeOptions.FirstPipeInstanceを指定し同名パイプが既にあれば失敗させる、クライアント側で接続後に所有者アカウントを検証するといった対策で軽減できる
応答が欲しい対話的な通信や秒間何十回も発生するやり取りにはファイル連携は向かない
双方が同時起動している必要がなく処理の証跡が残るファイル連携は、疎結合・非同期でよく監査ログを残したい連携で今も有力である
UIアプリとWindowsサービスを名前付きパイプで結ぶ構成を選んだ場合に限り、サービスは別アカウントで動くためPipeSecurityでACLを明示する必要がある。名前付きパイプを使わないサービスにはこの前提はない