Windowsのプロセス間通信をどう選ぶか ── 名前付きパイプ / TCP / gRPC / 共有メモリ / COM 判断表
· 小村 豪 · プロセス間通信, 名前付きパイプ, Windows, .NET, C#, gRPC, 共有メモリ, COM, 設計, 判断表, 技術相談
「UI とサービスを分けたら、間の通信はどうすればいいのか」「32bit のアプリから 64bit の DLL の機能を使いたい」「別プロセスの測定エンジンから画面へデータを流したい」。アプリを複数のプロセスに分ける設計は、堅牢性・権限分離・ビット数問題への現実解としてよく登場しますが、分けた瞬間に必ず「間の通信をどうするか」という選択が発生します。
当ブログではこれまで、共有メモリの落とし穴、TCP のフレーミング、子プロセスの安全な扱い、ファイル連携とロックと、個別の通信手段については書いてきました。ところが「そもそもどの手段を選ぶべきか」という総論がまだありませんでした。この記事では、Windows のプロセス間通信(IPC)の主要な選択肢──ファイル連携・名前付きパイプ・ローカル TCP・gRPC・共有メモリ・COM──の得意分野と落とし穴を、当ブログ恒例の判断表の形式で整理します。
1. まず結論
- 同一マシン内の要求応答(コマンドを送って結果をもらう)なら、名前付きパイプが第一候補です。OS 標準、ポート不要、Windows のアクセス制御と統合されていて、.NET からは
System.IO.Pipesで素直に書けます。1 - 将来ネットワーク越えの可能性があるなら、最初からローカル TCP か gRPC にします。パイプからソケットへの載せ替えは「あとで少し直す」では済まない差分になりがちです。ただし素の TCP はバイトストリームなので、フレーミングの設計が必須です。
- サービスや呼び出しの種類が増えて、自前プロトコルの維持が負担になってきたら gRPC です。proto によるスキーマ定義とコード生成、双方向ストリーミングが手に入り、.NET 8 以降は ASP.NET Core(Kestrel)が名前付きパイプをトランスポートにできます。2
- 大容量・高頻度のデータ(画像フレーム、波形)だけ共有メモリにします。最速ですが同期を全部自分で設計することになるので、制御メッセージまで共有メモリに乗せない、が鉄則です。3
- 疎結合・非同期でよく、監査ログを残したい連携ならファイル連携が今も有力です。ただし成否は排他制御の設計で決まります。
- COM(アウトプロセス)は新規設計の第一候補にはしませんが、VBA・他言語からの利用や 32bit/64bit ブリッジという文脈では今も現役の道具です。4
- どの手段を選んでも、メッセージの区切り・バージョン番号・タイムアウト・再接続という共通の設計課題からは逃げられません(第 6 章)。手段選びと同じくらい、ここに時間を使ってください。
2. 選択肢の素性
2.1 ファイル連携 ── 疎結合・非同期・監査可能
「A が出力フォルダーにファイルを置き、B が拾って処理する」という古典的な連携です。双方が同時に起動している必要がなく、処理の証跡がファイルとして残り、障害時には人間がファイルを直接見て・直して再投入できる。リアルタイム性を要求されないバッチ的な連携では今でも強力です。
落とし穴はほぼ一点、排他制御に集約されます。「書き込み途中のファイルを読んでしまう」「2 つの処理が同じファイルを取り合う」は定番事故で、一時ファイル名で書いてからリネームする等の定石を踏む必要があります。詳細は「ファイル連携とロックのベストプラクティス」にまとめてあるので、この方式を選ぶ場合は必ず参照してください。応答が欲しい対話的な通信、秒間何十回も発生するやり取りには向きません。
2.2 名前付きパイプ ── 同一マシンIPCの本命
名前付きパイプは Windows がカーネルで提供する双方向の通信路で、同一マシン内のクライアント・サーバー型 IPC の本命です。.NET では NamedPipeServerStream / NamedPipeClientStream で扱い、1 つのパイプ名に複数クライアントが接続できます。5 TCP と違ってポート番号の管理が不要で、ファイアウォールにも引っかかりません。
実務で押さえるべきポイントを挙げます。
- メッセージモードが使える。
PipeTransmissionMode.Messageを指定すると、書き込み 1 回分が 1 メッセージとして区切られて届きます。TCP で必須になる length プレフィックスなどのフレーミングを OS が肩代わりしてくれる、実務上大きな利点です(受信側はIsMessageCompleteで 1 メッセージを読み切る必要があります。第 5 章参照)。 - 既定のアクセス権は意外と緩い。 パイプの既定のセキュリティ記述子は、LocalSystem・管理者・作成者にフルコントロールを与える一方、Everyone と匿名アカウントにも読み取りを許可します。6 同一ユーザーのプロセス間なら
PipeOptions.CurrentUserOnlyを付けるだけで「同じユーザーが作った相手としか接続しない」を強制でき、これを既定の作法にすることをおすすめします。7 異なるアカウント間(サービスとの通信など)はPipeSecurityで ACL を明示します。 - パイプ名は全員から見える名前空間にある。 パイプ名は
\\.\pipe\配下の単一の名前空間に置かれ、マシン上の他のユーザーのプロセスからも見えます。ここで注意すべきなのが名前の占有(スクワッティング)です。悪意あるプロセスが先に同じ名前でサーバーを立てて待ち受ければ、クライアントはそちらに接続してしまいます。サーバー側はPipeOptions.FirstPipeInstanceを指定して同名パイプが既にあれば失敗させる、クライアント側は接続後にパイプの所有者アカウントを検証する、といった対策を、権限の異なるユーザーが同居するマシンでは入れておくべきです。8 - 権限境界を越える通信ができる。 UAC で分離された「標準権限の UI + 管理者権限のブローカー」の間の通信路としても定番です。ただしこの構成では
CurrentUserOnlyが使えません(同一ユーザーでも昇格レベルまで一致していることを要求するためです7)。ACL を明示的に設計する必要があり、具体的な作りは「管理者権限の分離(ブローカー)」で詳しく書いています。
弱点は、マシンをまたぐ通信に事実上向かないこと(仕様上は可能ですが運用面の制約が多い)、Windows 以外との相互接続に使いにくいことです。その要件が見えているなら TCP / gRPC を選びます。
2.3 ローカルTCP ── 言語・OSをまたぐ汎用性
localhost に対する TCP 接続は、およそどんな言語・ランタイム・OS からでも喋れる最も汎用的な IPC です。「Linux 上の解析エンジンと Windows の UI」のような混在構成では、まず TCP(またはその上の HTTP/gRPC)が候補になります。
注意点は 3 つです。
- バイトストリームである。 TCP には「送った単位で届く」という性質はありません。
Sendした 3 つのメッセージが 1 回のReceiveで連結されて届くのも、1 つのメッセージが分割されて届くのも正常です。length プレフィックスなどのフレーミングをアプリ層で設計する必要があり、これを省いたコードは「たまたま動いている」だけです。詳細は「TCPでSendした単位ごとにReceiveできるという誤解」を参照してください。 - 待ち受けの公開範囲を絞る。 同一マシン内の通信のつもりでも、
0.0.0.0で待ち受ければネットワーク上の他のマシンから接続できてしまいます。ローカル IPC なら127.0.0.1(ループバック)にバインドするのが原則です。それでも同一マシン内の別ユーザーからは接続できるため、相手の確認が必要ならアプリ層での認証を足します。パイプのような OS 統合のアクセス制御がない点は明確な差です。 - ポートの運用が付いて回る。 固定ポートは他のソフトと衝突し得ますし、ファイアウォール製品が「不審な待ち受け」として検出することもあります。ポート番号の変更手段は最初から設計に入れておきます。
2.4 gRPC ── スキーマとコード生成を買う
素のソケット + 自前プロトコルと比べたとき、gRPC が提供するのは通信そのものというより開発の枠組みです。proto ファイルでサービスとメッセージを定義すれば、シリアライズ・フレーミング・クライアント/サーバーのコードがすべて生成され、双方向ストリーミング(サーバーからのプッシュ通知)も言語機能のように書けます。「メッセージが増えるたびに自前プロトコルの switch 文とドキュメントを直す」フェーズに入ったら、この枠組みが効きます。
.NET 8 以降は ASP.NET Core(Kestrel)が TCP だけでなく Unix ドメインソケットと名前付きパイプをトランスポートとして直接サポートします。8 サーバー側は ListenNamedPipe を呼ぶだけで、PipeSecurity によるアクセス制御も設定できます。2 「通信路はパイプのままポートレス・ACL 統合、プロトコル層は gRPC」という組み合わせは、UI + サービス分離(第 4 章)で有力な選択肢です。
一方で、小規模なツール間通信にはオーバーキルになりがちです。gRPC サーバーを立てるということは ASP.NET Core のホスティング基盤を抱えるということで、配布物・依存関係・起動コストが増えます。コマンドが 2〜3 種類しかないツール同士なら、名前付きパイプ + JSON(第 5 章)のほうが総コストは安い、という線引きは持っておいてください。「proto に書きたいメッセージが 10 を超えた」「ストリーミング通知が本質的に必要」「相手が .NET 以外」のいずれかに当てはまってから、で遅くありません。
2.5 共有メモリ(メモリマップトファイル) ── 最速、ただし同期は全部自前
同一マシン内で最速の IPC は共有メモリです。.NET では MemoryMappedFile.CreateNew で名前付きの共有メモリを作り、複数プロセスから同じバイト列を直接読み書きできます。3 コピーもシリアライズも介在しないので、画像フレームや波形データのような「大きくて速い」データにはこれ一択と言ってよい性能が出ます。
ただし、共有メモリは「速いパイプ」ではありません。同じバイト列が見えるだけで、同期は 1 バイト分も提供されません。書き込み途中のデータを読まない仕組み、相手の生死の検出、片方が異常終了したあとの復旧──全部自分で設計することになります。リングバッファ構成やレイアウトのバージョン管理まで含めた設計論は「共有メモリの落とし穴と実務ベストプラクティス」に一本まとめてあります。
実務での使いどころは明確で、データ面(data plane)だけを共有メモリに乗せ、制御面(control plane)は名前付きパイプなど別のチャネルに逃がす構成です(第 4 章の構成 3)。開始・停止・設定変更のような制御メッセージまで共有メモリで頑張り始めたら、設計を見直すサインです。
2.6 COM(アウトプロセス) ── 新規の第一候補ではないが、現役の場面がある
COM のアウトプロセスサーバー(EXE サーバー)は、Windows が古くから持つ「別プロセスのオブジェクトをローカル関数のように呼ぶ」仕組みです。4 新規のアプリ間通信で第一候補にすることはもうありませんが、次の文脈では今も実用的です。
- 32bit/64bit ブリッジ: 32bit アプリから 64bit の DLL(またはその逆)は同一プロセスにロードできませんが、アウトプロセス COM なら境界をまたげます。COM 基盤がマーシャリングを肩代わりするため、呼び出し側のコードをほぼ変えずに済みます。実例は「32bit→64bit COMブリッジ実例」に書きました。
- VBA・他言語からの利用: Excel VBA など古い実行環境から .NET の機能を呼ばせたい場合、COM として公開するのが今も一番素直な経路です。
- 既存の COM 資産との連携: 相手が COM でしか喋れないなら、こちらも COM で喋るのが最短です(COM 自体の解説は「COM・ActiveX・OCXとは何か」)。
新規採用をためらう理由は、レジストリ登録を伴う配布の面倒さ、インターフェイス設計と参照カウントの学習コスト、そしてトラブル時の調査の難しさです。「32/64 ブリッジが目的なら、64bit 側をただのヘルパープロセスにして名前付きパイプで喋る」という代替案(第 4 章の構成 2)と比較してから決めてください。
2.7 古典的な手段 ── 新規では選ばない
Windows には他にも WM_COPYDATA(ウィンドウメッセージでデータを送る)、クリップボード、DDE、メールスロットといった IPC 手段があり、公式の IPC 概要ページには今も並んでいます。4 ただ、ウィンドウの存在が前提だったり、廃止が進んでいたり(リモートメールスロットは廃止の途上です)で、新規設計で選ぶ理由はほぼありません。既存アプリの保守で出会ったときに分かれば十分です。
3. 判断表
| 観点 | ファイル | 名前付きパイプ | ローカルTCP | gRPC | 共有メモリ | COM |
|---|---|---|---|---|---|---|
| 通信範囲 | 共有フォルダーでマシン越え可 | 同一マシンが実用範囲 | マシン越え可 | マシン越え可 | 同一マシン限定 | 同一マシンが実用範囲 |
| 通信モデル | ファイル受け渡し(非同期) | ストリーム+メッセージモード | バイトストリーム | RPC+ストリーミング | 共有状態 | メソッド呼び出し |
| サーバー→クライアント通知 | ✕(ポーリング) | ○ | ○ | ◎(双方向ストリーミング) | △(イベント併用) | △(作れるが複雑) |
| 権限境界越え(UAC・サービス) | ○(フォルダーACL) | ◎(PipeSecurity) | △(認証は自前) | △〜○(パイプトランスポートなら◎) | ○(ACL可、設計は難) | ○ |
| 32/64・言語混在 | ◎ | ○ | ◎ | ◎(proto から各言語へ生成) | △(ABI設計が必須) | ○(ブリッジは得意) |
| 実装コスト | 低 | 低〜中 | 中(フレーミング自前) | 中(基盤導入) | 高 | 高(新規には) |
| デバッグのしやすさ | ◎(中身がファイルで残る) | ○ | ○(キャプチャ可能) | △(HTTP/2+バイナリ) | △(症状が派手) | △ |
| スループット/レイテンシ | 低 | 中〜高 | 中 | 中 | ◎ | 中 |
補足をひとつ。「◎ が多い手段」を選ぶのではなく、要件に効く行だけを見て消去法で絞るのが正しい使い方です。たとえば「秒間 30 フレームの画像」と決まった時点で、データ面は共有メモリ一択です。
4. 定番構成の例
判断表を個別要件に当てはめると、実務では次の 3 つの構成に落ちることが多いです。
構成 1: UI アプリ + Windows サービスの分離。 常駐処理や特権が必要な処理をサービスに置き、UI は普通のユーザープロセスにする構成です(サービス側の作り方は同日公開の「Windowsサービス記事」を参照)。通信は名前付きパイプが本命で、プロトコルは JSON メッセージ+メッセージモード(またはバイトモード+length プレフィックス)から始めるのが手堅く、呼び出しの種類が育ってきたら gRPC の名前付きパイプトランスポートへ移行する道もあります。2 サービスは別アカウント(LocalService など)で動くため CurrentUserOnly は使えず、PipeSecurity で「Users に読み書きを許可、リモートは拒否」といった ACL を明示するのがポイントです。
構成 2: 32bit アプリ → 64bit 機能のブリッジ。 64bit でしか動かない DLL・ドライバー SDK を 32bit の既存アプリから使いたい場合、64bit 側を別プロセスに切り出します。実装は 2 通りで、(a) 64bit のヘルパープロセスを立てて名前付きパイプで喋る、(b) 64bit のアウトプロセス COM サーバーにする、です。呼び出し側が VBA や古い言語なら (b) が素直で、C# 同士なら (a) のほうが配布も調査も楽です。(a) の場合、ヘルパープロセスの起動・監視・親子連動終了は「子プロセスを安全に扱う」で書いた Job Object のパターンをそのまま使ってください。
構成 3: 測定エンジン → 表示の高頻度データ。 計測・画像処理エンジンを別プロセスにして UI へデータを流す構成では、制御(開始・停止・設定)は名前付きパイプ、データ(フレーム・波形)は共有メモリ+名前付きイベントという 2 チャネル構成が定番です。制御は秒に数回なのでパイプで十分、データは共有メモリでゼロコピーに近づける。チャネルを分けることで、データ側の設計(リングバッファなど)を制御の都合と切り離して最適化できます。エンジンや外部機器の状態表示は「外部機器の状態表示」も参照してください。
5. 実装例 ── 名前付きパイプの非同期サーバーとクライアント
構成 1 を想定した、.NET 8 での最小構成を示します。メッセージモード・複数クライアント対応・CurrentUserOnly(同一ユーザー間の通信の場合)・切断処理まで含めた形です。プロトコルは「UTF-8 の JSON を 1 メッセージ 1 通」とし、必ず version フィールドを持たせます。
まずサーバー側です。接続を受けるたびに新しいサーバーストリームを作り直し、クライアントごとの処理はタスクに切り離します。
using System.IO.Pipes;
using System.Text.Json;
public sealed class PipeServer(string pipeName)
{
// camelCase・大文字小文字非区別のWeb既定。System.Text.Jsonの既定は
// 大文字小文字を区別するため、これを共有しないと "version" が
// Request.Version に束縛されず、正しい要求が unknown_type に落ちる
internal static readonly JsonSerializerOptions JsonOptions =
new(JsonSerializerDefaults.Web);
public async Task RunAsync(CancellationToken ct)
{
while (!ct.IsCancellationRequested)
{
var pipe = new NamedPipeServerStream(
pipeName,
PipeDirection.InOut,
NamedPipeServerStream.MaxAllowedServerInstances,
PipeTransmissionMode.Message, // 1書き込み=1メッセージ
PipeOptions.Asynchronous | PipeOptions.CurrentUserOnly);
await pipe.WaitForConnectionAsync(ct);
_ = Task.Run(() => HandleClientAsync(pipe, ct), ct); // 接続ごとに分離
}
}
// 1メッセージの上限。相手が巨大なメッセージを送ってきても
// サービス側のメモリを守る(IPCの相手も外部入力。第6章)
private const int MaxMessageBytes = 1024 * 1024;
private static async Task HandleClientAsync(
NamedPipeServerStream pipe, CancellationToken ct)
{
await using (pipe)
{
var buffer = new byte[64 * 1024];
try
{
while (!ct.IsCancellationRequested)
{
// メッセージモードでも、1回のReadで1メッセージ全部が
// 読めるとは限らない。IsMessageComplete まで読み切る
using var ms = new MemoryStream();
do
{
int n = await pipe.ReadAsync(buffer, ct);
if (n == 0) return; // クライアントが切断した
ms.Write(buffer, 0, n);
if (ms.Length > MaxMessageBytes) return; // 上限超過。切断する
} while (!pipe.IsMessageComplete);
byte[] response = Dispatch(ms.ToArray());
await pipe.WriteAsync(response, ct);
}
}
catch (IOException)
{
// このクライアントとの通信路が壊れただけ。
// サーバー全体は止めず、他の接続の処理を続ける
}
}
}
private static byte[] Dispatch(byte[] payload)
{
Request? req;
try { req = JsonSerializer.Deserialize<Request>(payload, JsonOptions); }
catch (JsonException) { req = null; }
// 形式不正・未知のバージョン・未知のtypeはここで検査して拒否する
object result = req switch
{
null => new { version = 1, error = "bad_request" },
// version 未指定(0に束縛される)や未知のバージョンはここで拒否する
{ Version: not 1 } => new { version = 1, error = "version_unsupported" },
{ Type: "getStatus" } => new { version = 1, running = true },
{ Type: "startJob" } => new { version = 1, jobId = StartJob(req) },
_ => new { version = 1, error = "unknown_type" },
};
return JsonSerializer.SerializeToUtf8Bytes(result, JsonOptions);
}
}
public sealed record Request(int Version, string Type, JsonElement? Body);
クライアント側は「接続 → 要求 → 応答」を 1 つのメソッドに閉じ、タイムアウトと再試行を最初から入れておきます。
using System.IO.Pipes;
using System.Text.Json;
public sealed class PipeClient(string pipeName)
{
// idempotent: この要求は2回届いても安全だと呼び出し側が宣言したときだけ
// 再試行する。既定は「再試行しない」
public async Task<TResponse?> RequestAsync<TResponse>(
object request, CancellationToken ct, bool idempotent = false)
{
for (int attempt = 1; ; attempt++)
{
// 接続だけでなく要求→応答の交換全体に上限時間を設ける。
// サーバーが接続だけ受けて応答を書かずに固まった場合の
// 無限待ちを防ぐ
using var deadline =
CancellationTokenSource.CreateLinkedTokenSource(ct);
deadline.CancelAfter(TimeSpan.FromSeconds(10));
try
{
using var pipe = new NamedPipeClientStream(
".", pipeName, PipeDirection.InOut,
PipeOptions.Asynchronous | PipeOptions.CurrentUserOnly);
// 無限に待たない。サーバー未起動なら例外になる
await pipe.ConnectAsync(timeout: 3000, deadline.Token);
pipe.ReadMode = PipeTransmissionMode.Message;
await pipe.WriteAsync(
JsonSerializer.SerializeToUtf8Bytes(
request, PipeServer.JsonOptions),
deadline.Token);
using var ms = new MemoryStream();
var buffer = new byte[64 * 1024];
do
{
int n = await pipe.ReadAsync(buffer, deadline.Token);
if (n == 0) throw new IOException("サーバーが切断しました。");
ms.Write(buffer, 0, n);
} while (!pipe.IsMessageComplete);
return JsonSerializer.Deserialize<TResponse>(
ms.ToArray(), PipeServer.JsonOptions);
}
catch (OperationCanceledException) when (ct.IsCancellationRequested)
{
throw; // 呼び出し側のキャンセル。再試行しない
}
catch (Exception ex) when (
ex is IOException or TimeoutException or OperationCanceledException
&& idempotent && attempt < 3)
{
// サーバー再起動中などの一時的な失敗を再試行する。
// 「送ったが応答を読む前に切れた」ケースでは要求が既に実行済みの
// 可能性があるため、startJob のような副作用のある要求は
// 既定どおり再試行せず、要求IDで重複を弾ける設計にしてから
// idempotent: true を渡す(第6章)
await Task.Delay(500 * attempt, ct);
}
}
}
}
このコードの設計判断を 3 つだけ補足します。
versionを最初のリリースから入れる。 UI とサービスは別々に更新される(片方だけ新しくなる)瞬間が必ず来ます。応答側が「知らないバージョンは明示的に拒否する」だけで、無言でおかしな動作をする事故が「分かるエラー」に変わります。- 接続は使い捨てにするか、常時接続にするかを決める。 上の例は要求のたびに接続する使い捨て型で、切断・再接続の状態管理が要らない代わりに高頻度の呼び出しには向きません。常時接続+サーバーからのプッシュ通知が必要になったら、その複雑さは gRPC の双方向ストリーミングに乗り換える判断材料になります。
- サービスと通信する場合は
CurrentUserOnlyを外し、PipeSecurityを設計する。 上の例は同一ユーザーのプロセス間を想定しています。相手が別アカウントのサービスなら、NamedPipeServerStreamAcl.Createで ACL 付きのサーバーストリームを作り、接続を許すグループを明示してください。6
6. プロトコル設計の共通注意 ── 手段を選んだあとの仕事
どの IPC を選んでも、通信の中身の設計には共通の課題があります。手段選びより、実はこちらのほうが事故の源です。
- メッセージの区切り(フレーミング): パイプのメッセージモードのように OS が区切ってくれる場合を除き、「どこからどこまでが 1 メッセージか」はアプリの責任です。共有メモリのレコード境界も同じ問題です。length プレフィックス方式を基本にしてください。
- バージョニング: メッセージに形式バージョンを含め、受信側は「知らないバージョンを明示的に拒否」します。両プロセスが常に同時に更新される保証は、同じインストーラーで配っていてもありません。
- タイムアウト: 「相手が応答しない」は必ず起きるものとして設計します。接続・要求・応答のそれぞれに上限時間を決め、無限待ちのコードを残さないこと。UI スレッドで同期的に待つのは論外です。
- 再接続と冪等性: 再試行するということは、同じ要求が 2 回届く可能性を作るということです。「2 回実行しても安全な要求か」を要求の種類ごとに分類し、安全でないもの(ジョブ投入など)には要求 ID を付けて重複を弾きます。
- 相手も外部入力として検証する: 同一マシン内の通信だと「相手は自分のアプリだから」と検証を省きがちですが、権限境界がある場合、IPC の相手はネットワークからの入力と同じ「信頼できない入力」です。管理者権限のブローカーやサービスは、標準権限のクライアントから届いたパスやコマンドをそのまま実行してはいけません。パイプ名の占有(2.2 節)も含め、「誰が」「何を」の両方を疑うのが権限境界越え IPC の作法です。
- 観測手段を残す: 通信ログ(少なくともメッセージ種別と相手・結果)を出せるようにしておくと、「繋がらない」「返ってこない」系の調査時間が桁で変わります。
7. まとめ
プロセス間通信の選択は、次の順で考えるとほぼ迷いません。まず同一マシン限定でよいか。限定でよいなら要求応答は名前付きパイプ、大容量高頻度データだけ共有メモリ、疎結合バッチはファイル連携。マシン越えや言語混在が見えているならローカル TCP か gRPC で、自前プロトコルの管理が負担になる規模なら gRPC。COM は新規の第一候補にはせず、32/64 ブリッジと VBA 連携の道具として温存する──この記事の判断表は、この流れを表にしたものです。
そして手段が決まったら、第 6 章の共通設計(フレーミング・バージョン・タイムアウト・再接続・相手の検証)を最初のリリースに入れること。IPC のトラブルは「手段の選択ミス」より「プロトコル設計を省いた」ことが原因のほうが圧倒的に多い、というのが実務での体感です。プロセス分割や通信方式の見直しは、まず「どのプロセスが・誰の権限で・何を・どの頻度でやり取りするか」の棚卸しから始めることをおすすめします。
関連記事
- 共有メモリの落とし穴と実務ベストプラクティス
- TCPでSendした単位ごとにReceiveできるという誤解 ── バイトストリームとして扱うための受信設計
- 管理者権限の分離(ブローカー) ── UAC境界をまたぐ設計
- Windowsサービスの作り方 ── Worker Serviceガイド
関連する相談領域
合同会社小村ソフトでは、プロセス分割・通信方式の設計レビュー、32bit/64bit ブリッジを含む既存資産との連携設計、「繋がらない・返ってこない」系の通信トラブルの原因調査を扱っています。
参考リンク
-
Microsoft Learn, How to: Use Named Pipes for Network Interprocess Communication. NamedPipeServerStream / NamedPipeClientStream による複数クライアント対応のサーバー・クライアント実装例について。 ↩
-
Microsoft Learn, Inter-process communication with gRPC and Named pipes. .NET 8 以降で Kestrel の ListenNamedPipe により gRPC を名前付きパイプ上で動かす構成と、PipeSecurity によるアクセス制御について。 ↩ ↩2 ↩3
-
Microsoft Learn, MemoryMappedFile Class. メモリマップトファイルの .NET API。CreateNew で作るファイルに紐付かない共有メモリが IPC 用途に適していることについて。 ↩ ↩2
-
Microsoft Learn, Interprocess communications. Windows が提供する IPC 機構(クリップボード、COM、WM_COPYDATA、DDE、ファイルマッピング、メールスロット、パイプ、RPC、Windows ソケット)の一覧と使い分けの指針について。 ↩ ↩2 ↩3
-
Microsoft Learn, NamedPipeServerStream Class. 名前付きパイプのサーバー側ストリーム。PipeTransmissionMode や PipeSecurity を指定するコンストラクターについて。 ↩
-
Microsoft Learn, Named Pipe Security and Access Rights. 名前付きパイプの既定のセキュリティ記述子が Everyone と匿名アカウントに読み取りを許可することと、アクセス権の構成について。 ↩ ↩2
-
Microsoft Learn, PipeOptions Enum. CurrentUserOnly が「同じユーザーが作成した相手」との接続のみを許可し、Windows ではユーザーアカウントに加えて昇格レベルまで検証することについて。 ↩ ↩2
-
Microsoft Learn, Inter-process communication with gRPC. gRPC を IPC に使う際のトランスポート(Unix ドメインソケット、名前付きパイプ)と、サーバーの所有者検証・偽装(impersonation)対策などのセキュリティ考慮事項について。 ↩ ↩2
関連する記事
同じタグを共有する最新の記事です。さらに近い話題で知識を深められます。
Windowsアプリのデータ保存先の選び方 ── SQLite / JSON / レジストリ / Access 判断表
Windowsデスクトップアプリのデータをどこに・何で保存するか。AppData/ProgramDataの使い分け、SQLite・JSONファイル・レジストリ・Access(.accdb)それぞれの得意分野と落とし穴を判断表つきで整理し、破損対策やビット数問題まで実務目線で...
Windowsサービスの作り方と運用 ── タスクスケジューラとの使い分けからBackgroundServiceのサービス化まで
常駐処理をWindowsサービスにすべきか、タスクスケジューラで足りるのか。判断表と、.NET Worker Service(UseWindowsService)によるサービスの作り方、実行アカウント・回復オプション・イベントログ・安全な停止処理まで、運用に乗せるための設計...
WinFormsの高DPI対応 ── 4Kモニターでぼやける・崩れる原因と現実的な対処
4Kモニターや150%スケーリングでWinFormsアプリがぼやける・レイアウトが崩れる原因を、DPI仮想化とDPI認識モード(System Aware / Per-Monitor V2)から整理します。.NET/.NET Frameworkそれぞれの設定方法、AutoSc...
C#でSQLiteを業務アプリに使う ── WALモード・排他制御・破損対策・EF Coreとの使い分け
Microsoft.Data.SqliteでSQLiteを業務Windowsアプリに組み込む実務知識を整理します。接続文字列とプーリング、WALモードの仕組み、SQLITE_BUSYと書き込み一本化、トランザクションによる高速化、型マッピングの罠、VACUUM INTOによ...
IEモードの次はWebView2でいいのか ── ActiveXが動かない制約と現実的な移行設計
WebView2の基本構造、EvergreenとFixed Versionの配布戦略、ユーザーデータフォルダーの罠、ネイティブとWebの連携方法、そして「ActiveXは動かない」という制約を踏まえたIEモード依存システムからの現実的な移行順序を、社内システム目線で整理します。
関連トピック
このテーマと近いトピックページです。記事を起点に、関連するサービスや他の記事へ進めます。
Windows技術トピック
Windows 開発、不具合調査、既存資産活用の技術トピックをまとめた入口です。
ActiveX / 移行テーマ
COM / ActiveX / OCX を残すか、包むか、置き換えるかを整理するトピックです。
このテーマがつながるサービス
この記事は次のサービスページにつながります。近い入口からご覧ください。
Windowsアプリ開発
業務アプリ、装置連携、通信ツールなどの Windows ソフト開発を支援します。
技術相談・設計レビュー
改修方針、設計レビュー、既存資産の扱いを整理するための技術相談です。
著者プロフィール
記事の著者プロフィールページです。
小村 豪
合同会社小村ソフト 代表
Windows ソフト開発、技術相談、不具合調査を中心に、既存資産が残る案件や原因が見えにくい障害調査に強みがあります。
公開リンク