別々のプロセスで起動したアプリケーションやライブラリで相互に通信する方法のサンプルコードです。今回は共有メモリ、MemoryMappedFile
を使います。
.NET Framework 4.0 以降に導入された技術のようです。
今回のサンプルは1つ目の Console アプリで入力した文字列を、2つ目の Console アプリ、WPF アプリ、Unity でそれぞれ読み取って表示するものになります。
目次
概要
処理の概要を説明すると、同じ名前で MemoryMappedFile を開くと、異なるプロセスでも同じメモリ領域にアクセスできるようになり、 MemoryMappedViewAccesor や MemoryMappedViewStream を通して値の読み書きができます。
MemoryMappedFile には、ファイルに関連付けて操作が終了するとファイルに保存される永続化と、メモリでのみ保持され操作が終了するとGCで開放される非永続化があります。
利用できるデータ型はプリミティブ型( String 除く)と Array
バイナリにシリアライズしてしまえば何でも送れそうです。 最小限のことをライトにやるには使えるかもしれないので覚えておいても良いでしょう。
MemoryMappedFile のより詳しい情報は公式をご覧下さい。
実装例
Console
送信側の Console アプリのサンプルコードです。
static void Main(string[] args) { Console.WriteLine("Please enter a message, and then press Enter."); using (var sharedMemory = MemoryMappedFile.CreateNew("SharedMemory", 1024)) { while (true) { var str = Console.ReadLine(); var data = str.ToCharArray(); using (var accessor = sharedMemory.CreateViewAccessor()) { accessor.Write(0, data.Length); accessor.WriteArray(sizeof(int), data, 0, data.Length); } } } }
続いて受信側の Console アプリです。同じ値が取れたら間引いてます。
static void Main(string[] args) { using (var sharedMemory = MemoryMappedFile.OpenExisting("SharedMemory")) { var latestMsg = string.Empty; while (true) { using (var accessor = sharedMemory.CreateViewAccessor()) { var size = accessor.ReadInt32(0); var data = new char[size]; accessor.ReadArray<char>(sizeof(int), data, 0, data.Length); var str = new string(data); if (latestMsg != str) { latestMsg = str; Console.WriteLine("Data :" + str); } } Thread.Sleep(100); } } }
WPF
受信側の WPF アプリのサンプルコードです。
Loadのイベントで処理して、XAML で追加した textBlock
に表示しています。
private async void MainWindow_Loaded(object sender, RoutedEventArgs e) { using (var sharedMemory = MemoryMappedFile.OpenExisting("SharedMemory")) { await Task.Run(() => { var latestMsg = string.Empty; while (true) { using (var accessor = sharedMemory.CreateViewAccessor()) { var size = accessor.ReadInt32(0); var data = new char[size]; accessor.ReadArray<char>(sizeof(int), data, 0, data.Length); var str = new string(data); if (latestMsg != str) { latestMsg = str; Dispatcher.Invoke(() => textBlock.Text += ("Data :" + str + "\r\n")); } } Thread.Sleep(100); } }); } }
Unity
最後は受信側の Unity アプリのサンプルコードです。 (動作確認は Editor でのみ)
async void Start() { var sharedMemory = MemoryMappedFile.OpenExisting("SharedMemory"); await Task.Run(() => { var latestMsg = string.Empty; while (true) { using (var accessor = sharedMemory.CreateViewAccessor()) { var size = accessor.ReadInt32(0); var data = new char[size]; accessor.ReadArray<char>(sizeof(int), data, 0, data.Length); var str = new string(data); if (latestMsg != str) { latestMsg = str; Debug.Log("Data :" + str); } } Thread.Sleep(100); } }); }
サンプルプロジェクト
ソースコード一式は以下においてあります。
参考
以下のサイトを参考にさせていただきました。ありがとうございます。