メモ日記

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

プロセス間通信を試した2(イベントハンドラ設定)

前回より

プロセス間通信をC#を実装するということで、 それのサンプルを自分なりに調べて作ってみた。

それで前回とりあえず通信できたけれど、 イベントハンドラを実装していなかったので、 今回はそれらを実装する。

ソースコード

共通で使うライブラリ

細かな作り方等々(ライブラリの参照の追加、usingを追記する)は前回を参照。

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

namespace SampleIpcEventHandlerLib
{
    public class SampleRemoteObject : MarshalByRefObject
    {
        public class SampleRemoteObjectEventArg : EventArgs
        {
            public string command { get; set; }
            public SampleRemoteObjectEventArg(string cmd)
            {
                command = cmd;
            }
        }

        public delegate void CallEventHandler(SampleRemoteObjectEventArg e);
        public event CallEventHandler getData;

        public void sendData(string cmd)
        {
            if (getData != null)
            {
                getData(new SampleRemoteObjectEventArg(cmd));
            }
        }
    }
}

前回から追記変更した箇所としては、 EventArgs関連のクラスを追加したこと、 デリゲートとかeventとかを追加したこと。 クライアントがデータを送信するのに使うメソッドを追加したこと。

名前の付け方等々いろいろ突っ込みがあると思うけれど、 自分がわかりやすいように付けてみた。

getDataというのにサーバー側でイベントハンドラ用のメソッドを設定していく感じ。

クライアントはsendDataメソッドを呼び出してデータを送信する感じ。

サーバー側

こちらも細かなところは前回記事参照。

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

using SampleIpcEventHandlerLib;

namespace SampleIpcEventHandlerServer
{
    class Program
    {
        static void Main(string[] args)
        {
            // 起動時のメッセージ 黒い画面ではクライアントサーバーを間違えたため
            Console.WriteLine("Server Start");

            // サーバーオブジェクト生成
            IpcServer server = new IpcServer();

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

    class IpcServer
    {
        public SampleRemoteObject remoteObject;

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

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

            // リモートオブジェクト生成
            remoteObject = new SampleRemoteObject();
            // イベントハンドラ設定
            remoteObject.getData += new SampleRemoteObject.CallEventHandler(
                getData);
            RemotingServices.Marshal(remoteObject, "test", typeof(SampleRemoteObject));

        }

        /**
         * イベントハンドラに設定するメソッド
         * メッセージが送られるとこれが呼ばれる。
         * 
         * */
        void getData(SampleRemoteObject.SampleRemoteObjectEventArg e)
        {
            Console.Write("Received:");
            Console.WriteLine(e.command);
        }
    }
}

前回よりいろいろ変更した箇所はあり、 リモートオブジェクト生成の箇所でイベントハンドラを設定していること、 イベントハンドラ用のメソッドを定義したことくらい。

mainメソッドでは入力待ちして イベントハンドラ用のメソッドでCUIにメッセージ表示みたいな動作。

クライアント側

こちらも(ry

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

using SampleIpcEventHandlerLib;

namespace SampleIpcEventHandlerClient
{
    class Program
    {
        static void Main(string[] args)
        {
            // 起動時のメッセージ 黒い画面ではクライアントサーバー間違えたため
            Console.WriteLine("Client Start");

            // クライアントオブジェクト生成
            IpcClient client = new IpcClient();

            // 入力用文字列
            string str = "";
            while(true)
            {
                str = Console.ReadLine();
                client.remoteObject.sendData(str);
            }
        }
    }

    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;
        }
    }
}

サーバー側に比べるとそこまで変更していなくて、 メッセージを送信するときにRemoteObjectで定義したsendDataメソッドを使って、 データを送信するようにしているのみ。

実行

実行方法は前回と変わってなくて、サーバー側を起動後、 クライアント側を起動。クライアント側でなにか文字を入力すると サーバー側のコンソールに文字列が表示されるという動作。

さいごに

これでプロセス間通信ができたと思う。 remoteObjectの変数をpublicにしていたりいろいろあるけれど、 これをもとにいろいろ変更すれば今作っているプログラムに使えそう。

疑問に思ったことと言えば双方向にする場合。 単純に両方にサーバーとクライアントの機能を実装すればいいかなと思ったけれど、 クライアント側のリモートオブジェクトを作るときに、 サーバー側があること前提になっているので、 うまくその辺をつくらないといけないのかなと。 サーバー側がないとクライアント側で例外が発生したような気がする。 自分が作ってるプログラムでは双方向にする必要は現在はないので深くは考えていない。

それからサーバー側クライアント側と順に起動して、 実行できたことを確認した後、サーバー側を再起動して、 そのあとクライアント側から文字列を送ると例外が発生した。

プロセス間通信のサンプルはなぜかGUIのサンプルしか見付けられなくて、 ボタン処理の実装等々のため複雑に見えたので、 自分用にCUIのサンプルができたのは良かったと思いたい。