メモ日記

実生活やネットで経験したこと調べたことをまとめたサイト

プロセス間通信を試した

C#で実装

プロセス間通信にちょっと興味がわいたので、 それを作ってみた。 プログラミング言語はC#を使ってみた。

以前Linux上でC言語を使って作ったことはあったけれど、 Windows上のC#で実装したことはなかったので、 どんなものか調べてみたくて今回実装にチャレンジした。

ソースコード

ソースコードはサーバー側とクライアント側、 それから両方で使うライブラリも用意してみた。

ライブラリにはリモートオブジェクトというものを定義。 そのオブジェクトをもとに、 サーバー側でIPCの定義を行い、 クライアント側でデータを入れたりするような感じがする。 正直よくわからん。

それからソースコードの上の方で、次のものを定義。

using System.Runtime.Remoting;
using System.Runtime.Remoting.Channels;
using System.Runtime.Remoting.Channels.Ipc;

それから上のコードでIpcが見つからないということが起きたけれど、 これはソリューションエクスプローラーを右クリックして、 追加->参照でSystem.Runtime.Remotingを追加。

共通で使うライブラリ

ファイル->新規作成->プロジェクトと進み、その中のクラスライブラリから作る。

namespace SampleIpcLib
{
    public class SampleRemoteObject : MarshalByRefObject
    {
        public string Command { get; set; }
        /**
         * プロセス間通信はしばらく通信が行われないと接続が切断されてしまう。
         * 以下のreturn nullで、それ無効化できる。
         * 
         * */
        public override object InitializeLifetimeService()
        {
            return null;
        }
    }
}

ソースコードではCommandというstring型の変数を定義したのみ。 それから接続が切れてしまうということがあるらしいので、 接続時間関係のなにかを無効化できるらしいおまじないを追加した。

上記のソースはDLLにして、 これから作るサーバー側クライアント側のプロジェクトから参照する。

サーバー側

コンソールアプリを新規作成して、次のソースコードのように変更する。 usingあたりは端折った。

namespace SampleIpcServer
{
    class Program
    {

        static void Main(string[] args)
        {
            IpcServer server = new IpcServer();

            // 入力待ち(終了させないため)
            Console.ReadLine();
        }
    }

    class IpcServer
    {
        public SampleRemoteObject remoteObject;

        public IpcServer()
        {
            // IPC Channel作成
            IpcServerChannel ipcChannel = new IpcServerChannel("ipcSample");

            // チャンネル登録
            ChannelServices.RegisterChannel(ipcChannel, true);

            // リモートオブジェクト生成
            remoteObject = new SampleRemoteObject();
            RemotingServices.Marshal(remoteObject, "test", typeof(SampleRemoteObject));
        }
    }
}

こちらも上のほうで書いたusing ....Remotingを追加するのと、 ライブラリの参照を追加するのと、 作ったライブラリのusing ....を追加するのとという感じ。

クライアント側

サーバー側同様にこちらもコンソールアプリを新規作成。

namespace SampleIpcClient
{
    class Program
    {
        static void Main(string[] args)
        {
            // クライアントオブジェクト生成
            IpcClient client = new IpcClient();

            // リモートオブジェクトの現在値
            Console.WriteLine("{0}", client.remoteObject.Command);

            // 送信する文字列の入力
            client.remoteObject.Command = Console.ReadLine();

            client.remoteObject.Command = Console.ReadLine();
        }
    }

    class IpcClient
    {
        public SampleRemoteObject remoteObject;

        public IpcClient()
        {
            // クライアントチャンネル生成
            IpcClientChannel channel = new IpcClientChannel();

            // チャンネル登録
            ChannelServices.RegisterChannel(channel, true);

            // リモートオブジェクト取得
            remoteObject = Activator.GetObject(typeof(SampleRemoteObject),
                "ipc://ipcSample/test") as SampleRemoteObject;
        }
    }
}

これまたサーバー側と同様に、 上のほうで書いたusing ....Remotingを追加するのと、 ライブラリの参照を追加するのと、 作ったライブラリのusing ....を追加するのとという感じ。

実行

実行方法はサーバー側のプログラムを実行して、入力待ちの状態にさせて。 そのあとクライアント側のプログラムを実行する。 クライアント側で文字を入力する。 クライアント側は文字を2回入力させるようになっているので、 2回入力する。 サーバー側のプログラムはそのまま実行させたままの状態にして、 クライアント側をもう1度実行すると、 先程実行したときに最後に入力した文字列が表示されてから入力待ちの状態になる。 なので、入力した段階で文字列が反映されているっぽい。しらんけど。

ネットでいろいろ調べると、イベントハンドラでイベント駆動ができるっぽいので、 今度はそちらに挑戦してみたい。

とりま、データ(文字列)を他のプロセスから見れたというところまで。