【C#】コレ一択ッッ!?プロセス間通信(MemoryMapedFile)

スポンサーリンク

仕事の相手先とのアプリとの通信をしなきゃいけなくなって、相手先から「MemoryMappedFile(メモリマップトファイル)でやりましょう!!」って言われた。
プロセス間通信の手段の1つらしくて、SendMessage/PostMessageよりかは自由度が高いと感じた。
そして、今回は記載しないが、PythonでもMemoryMappedFileが可能なので重宝しそうである。
プロセス間通信に困っている人の手助けになればと思います。

プロセス間通信とは

ざっくり言うと『複数のローカルアプリが会話する為の通信』である。

今回は、そのプロセス間通信の手段の1つとして「MemoryMappedFile」を紹介する。

MemoryMappedFile(メモリマップトファイル)

Microsoftのページの説明のページは下記にある。
MemoryMappedFile クラス (System.IO.MemoryMappedFiles) | Microsoft Learn
説明が初心者にやさしくないッッ!!笑

イメージ

パソコン内のメモリを共有して、メモリの開始アドレスを指定して、読み書きする仕組みっぽい。

今回は分かりやすくサーバー側(書き込み側)クライアント側(読み込む側)で分けて書きます。

メモリ内のアドレス

Windows内のメモリ領域を共有します。Windows内の開始アドレスは知る必要はありません。ただ共有するメモリ領域のアドレスについては事前に相手先と決めておく事をオススメします。

なぜかというと、開始アドレスを間違えると、読み込んだ値が変わってしまうからです。
イメージを伝えたところで本題に入っていきたいと思います。

サーバー側を作ってみる(作る側)

操作画面(GUI)の説明

今回は読み込み開始位置(nudStartByte)を指定して、
ボタン(btnReadMapInt)を押すと
結果をテキスト(txtReult)に表示するような操作画面を作成する。

実際に作ってみる

メモリー領域を作ろうと思います。
ここで必要な事は【名前】と【サイズ(byte数)】です。

NameSpaceの指定

using System.IO.MemoryMappedFiles;

変数を定義

private MemoryMappedFile TestMemory;
private MemoryMappedViewAccessor Accessor;
private const int MemorySize = 70;

メモリーマップファイルを作成

今回はフォームロードのタイミングで作成する。
今回のメモリーマップは【名前:TestMemory】【サイズ:70】で行う。

private void frmMemoryMapServer_Load(object sender, EventArgs e)
{
TestMemory = MemoryMappedFile.CreateNew("TestMemory", MemorySize);
Accessor = TestMemory.CreateViewAccessor(0, MemorySize);
}

メモリーマップトファイルの作成関数[CreateNew(mapname,mapsize)]を使って作成します。

読み込み処理の作成

ボタンをクリックされたら、読み込み開始位置を取得し、読み込み結果を表示します。

private void btnReadMapInt_Click(object sender, EventArgs e)
{
//読み込み開始位置を取得
long startByte = (long)nudStartByte.Value;

//読み込み実施
Accessor.Read(startByte, out int value);

//結果を表示
txtResult.Text = value.ToString();
}

読み込んだ結果を表示するようにできました。
引き続いて、書き込む側を作成していきたいと思います。

クライアント側を作ってみる

操作画面(GUI)

今回は読み込み開始位置(nudStartByte)を指定して、
書き込む数値(nudValue)を取得して、
ボタン(btnWriteMapInt)を押すとMemoryMap上に書き込む操作画面を作成する。

実際に作ってみる

基本作り方はサーバーの時と同じになります。

NameSpaceの指定

using System.IO.MemoryMappedFiles;

変数を定義

private MemoryMappedFile TestMemory;
private MemoryMappedViewAccessor Accessor;
private const int MemorySize = 70;

メモリーマップファイルを読み込み

今回はフォームロードのタイミングで、指定されたMemoryMapedFileにアクセスします。
今回のメモリーマップは【名前:TestMemory】【サイズ:70】で行う。

private void frmMemoryMapServer_Load(object sender, EventArgs e)
{
TestMemory = MemoryMappedFile.OpenExisting("TestMemory");
Accessor = TestMemory.CreateViewAccessor(0, MemorySize);
}

メモリーマップトファイルを開く関数[OpenExisting(mapname)]を使ってアクセスします。

書き込み処理の作成

ボタンをクリックされたら[書き込み開始位置]と[書き込み数値]を取得し、書き込みを実施します。

private void btnWriteMapInt_Click(object sender, EventArgs e)
{
//書き込み開始位置を取得
long startByte = (long)nudStartByte.Value;

//書き込み数値
int value = (int)nudValue.Value;

//書き込み実施
Accessor.Write(startByte,value);
}

書き込みの処理ができたので、実際に動かしてみたいと思います。

動作確認結果

書き込んだ結果を無事に取得する事ができました。
例えば、読み込みの開始位置が違うと下記のようになります。

読み込みの開始位置を間違った場合、正確に取得できないので、しっかりとマップを共有しないといけません。

まとめ

今回MemoryMapedFile(メモリーマップトファイル)の紹介をさせていただきました。
これを知った時にSendMessageより自由度が高く、使いやすいと思いました。
今回の紹介では、Integer型の読み書きの紹介でしたが、他の型でも可能です。
また、文字を書き込みたい時の対処方法はまたの備忘録で書きたいと思います。

使った感じだと、内部で排他処理がされている可能性が高く、同時アクセスについてはあまり考慮せずに使えそうな感じでした。

ちなみにMemoryMapedFileが作成されていなかった場合は、「System.IO.FileNotFoundException」が発生します。

ぜひ、誰かの参考になればと思います。

コメント

タイトルとURLをコピーしました