⚡️

Windows の名前付きパイプでホスト間通信をしたい

2024/07/06に公開

TL;DR

解決したいこと

  • Windows で名前付きパイプを使ってホスト間通信をしたい

わかったこと

  • Windows の名前付きパイプを使ったホスト間通信は SMB プロトコルを使っている
  • 名前付きパイプは \\.\pipe\ から始まる特殊なパスにマウントされている
  • SMB は TCP ポート 445 を使っているため、ファイアーウォールで許可すると名前付きパイプのネットワークごしの通信ができる

内容

今回は、解決したいことについての技術的背景についての説明にとどめ、解決法はスコープとはしていません。そのため、具体的なコードやその手順については 参考 にした情報をまとめたので、そちらを参照してください。

はじめに

とある案件で、ASP.NET Core でホスティングする Windows サービスに対して、別の Windows マシンから名前付きパイプを利用したホスト間通信を行うという話がありました。IPC であるパイプを Windows でネットワークごしに通信するためのノウハウを持ち合わせていない上、ネットを探してもなかなか情報が見つからなかったです。

一つ一つの技術を丁寧に紐解いていくとシンプルな話になりますが、0 から組み上げようとしたときにそれなりに苦労したので、この話が誰かの役に立てば嬉しいです。

名前付きパイプとは

そもそも名前付きパイプとは何でしょうか。 Wikipedia の 名前付きパイプ によると

名前付きパイプ(英: named pipe)は、UNIXおよびUnix系の通常のパイプを拡張したもので、プロセス間通信の技法の1つ。(中略) 名前付きパイプは永続的で、(中略) ファイルのように扱うことができ、プロセス間通信 (IPC) を行うためにプロセスがオープンして使用する。

要するにプロセスがお互いにデータをやりとりするための通信手段がファイルのように扱え、特にそれに名前をつけて使えるようにしたのが名前付きパイプであるということです。

Windows では名前付きパイプは \\.\pipe\ の特殊なディレクトリにファイルとしてマウントされます。そのため、以下のようなコマンドを実行すると実際に結果が得られるはずです。

PS> Get-ChildItem -Path \\.\pipe\

そして、この名前付きパイプはネットワークごしにも通信することが可能です。パイプのパスを \\machine.example.com\\pipe\<pipe-name> のようにネットワーク名を指定することで接続できます。

この裏では、 Windows のコミュニケーションプロトコルである Server Message Block (SMB) が利用されています。SMB は、TCP 445 に相乗りする形で実装されているそうです。

Windows の FS として表現されているため、FS が提供するセキュリティの機能 (グループポリシー・ドメイン・etc) が利用できたりすることが利点です。

ASP.NET Core での名前付きパイプの利用

さて、C# ひいては ASP.NET Core で名前付きパイプを使うにはどうすればいいでしょうか。

公式ドキュメントによると Inter-process communication with gRPC and Named pipes | Microsoft Learn が紹介されていますが、 gRPC と名前付きパイプを組み合わせるという話になっています。

この後色々検証しましたが、ASP.NET Core では gRPC を使わないと名前付きパイプを使った IPC ができなかったのでどうやらピュアな HTTP 通信では名前付きパイプを使うことはできないようです。(もしできる方法があれば教えていただきたいです)

gRPC とは?

gRPC とは、Goole が作った RPC フレームワークで、ハイパフォーマンス・クロスプラットフォームであることが特徴です。HTTP/2 をトランスポート層で用いており、Protocol Buffers を共通言語 (IDL) として利用しています。その他にも双方向に通信できる機能があったりしますが、気になったら詳細を公式に求めると良いと思います。

プロトコルの実装に則した ベストプラクティス はありますが、シンタックスは簡単で以下のように記述します。

buy.proto
message BuyRequest {
  string id = 1;
  int32 quantity = 2;
  int32 price = 3;
}

message BuyResponse {
  string result = 1;
}

service MyService {
  rpc Buy(BuyRequest) returns (BuyResponse);
}

一言でいうと、 gRPC はこの proto (Protocol Buffers) を利用した RPC のためのフレームワークです。

実装の話

ASP.NET Core での gRPC のサポートは手厚く、プロジェクトファイルの中に PackageReference を入れ、 .proto ファイルを <Protobuf> で囲って定義してあげるだけで obj ディレクトリにスタブを生成してくれます。開発者は、このスタブを利用して Ser/De やマッピングを気にすることなくプロトコルバッファに定義した message や RPC を型安全に実装する作業に専念できます。

MyProj.csproj
<ItemGroup>
    <Protobuf Include="Protos\buy.proto" />
</ItemGroup>

まとめ

ここまでいろいろな技術的な話が続いてきましたが、最初のスコープである

Windows で名前付きパイプを使ってホスト間通信をしたい

という観点で問題を眺めると話はシンプルであることに気がつくはずです。というのも、それぞれの技術には以下の依存関係があり Windows で名前付きパイプを使ったホスト間の通信は SMB が使っている TPC 445 を通すことで達成可能ということが分かるからです。

参考

GitHubで編集を提案

Discussion