WCFで名前付きパイプを使ったプロセス間通信 - IronPython でサーバーとクライアントを実行

WCFで名前付きパイプを使ったプロセス間通信を実施してみる。
サービスは C# で、サーバー・クライアントは IronPython でコーディングしてみた。

使用した環境は以下の通り。

サービスの作成

まず、C# でサービスをコーディングする。サービスの定義には以下のような属性を使用する。

  • ServiceContract でサービスを定義
  • OperationContract でサービスで公開するメソッドを定義
  • ServiceBehavior でサービスの振る舞いを定義(サンプルではシングルトンを指定)
  • DataContract でサービスでやり取りするデータを定義
  • DataMember でデータのメンバーを定義
SampleService.cs
using System;
using System.Runtime.Serialization;
using System.ServiceModel;

namespace SampleLib
{
    //サービスインターフェース
    [ServiceContract]
    public interface ISampleService
    {
        [OperationContract]
        void AddData(SampleData data);
    }

    //サービスクラス
    [ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)]
    public class SampleService : ISampleService
    {
        //メソッドの実装
        public void AddData(SampleData data)
        {
            Console.WriteLine("data: id={0}, name={1}", data.Id, data.Name);
        }
    }

    //データクラス
    [DataContract]
    public class SampleData
    {
        [DataMember]
        public int Id;
        [DataMember]
        public string Name;
    }
}
ビルド

SampleService.cs をビルドしてアセンブリファイル(.dll)を作成。

>csc /target:library /out:SampleLib.dll SampleService.cs

サーバーの作成

サービスの公開に ServiceHost クラスを使用する。
今回は名前付きパイプを使うため、以下を使ってエンドポイントの設定を行う。

なお、シングルトンでサービスを公開するには ServiceHost のコンストラクタにサービスクラスのインスタンスを渡せばよい。(ただし、ServiceBehavior 属性で InstanceContextMode に Single を設定しておく必要あり)

sample_server.py
# coding: utf-8
import clr
clr.AddReference("System.ServiceModel")
clr.AddReference("SampleLib.dll")

from System import *
from System.ServiceModel import *
from SampleLib import *

#サービスをインスタンス化
service = SampleService()

#自己ホスト用のクラスをインスタンス化
host = ServiceHost(service)

#名前付きパイプのバインディングをインスタンス化
binding = NetNamedPipeBinding()

#ISampleService に対するエンドポイントを設定
host.AddServiceEndpoint(ISampleService, binding, "net.pipe://localhost/sample")

host.Open()

Console.WriteLine("press enter key to terminate service")
Console.ReadLine()

host.Close()

クライアントの作成

クライアントでは、サーバーで設定したエンドポイントと同じ設定を使って、ジェネリックな ChannelFactory をインスタンス化、CreateChannel でサービスのプロキシを取得してサービスの呼び出しを行う。

sample_client.py
# coding: utf-8
import clr
clr.AddReference("System.ServiceModel")
clr.AddReference("SampleLib.dll")

from System.ServiceModel import *
from SampleLib import *

binding = NetNamedPipeBinding()
factory = ChannelFactory[ISampleService](binding, "net.pipe://localhost/sample")
#サービスプロキシの取得
service = factory.CreateChannel()

data = SampleData()
data.Id = 100
data.Name = "テストデータ"

#サービスの実行
service.AddData(data)

factory.Close()

実行

サーバー実行
>ipy sample_server.py
press enter key to terminate service
クライアント実行
>ipy sample_client.py
サーバーの実行結果
>ipy sample_server.py
・・・
data: id=100, name=テストデータ