以前.NET Remotingで双方向通信 をやる方法を調べてまとめておいたのですが、要約するとクライアント側にあるdelegateオブジェクトを.NET Remotingを通じてサーバに渡しておけば、サーバーがそのdelegateを呼ぶことによってクライアント側の関数が呼び出されるというもの。
しばらくこの方法で使用していたのですが、このdelegateを呼び出す時によく分からないタイミングで
This remoting proxy has no channel sink which means either the server has no registered server channels that are listening, or this application has no suitable client channel to talk to the server.
などという非常に長いメッセージを持つ例外が発生、サーバー→クライアントの呼び出しが失敗してしまいました。
このメッセージをキーワードにして検索すると、文字数が多いため結構ピンポイントで同じ問題を扱っている海外サイトにヒット。どうやらdelegateを呼び出す時にサーバー側がクライアントのどのポートにどのプロトコルで通信すればいいのか分からなくなるらしいです。
今回はサーバーへの接続を開始する前にクライアント側で以下の処理をして、クライアントが受け付けるチャンネル(sink)を宣言しました。
int portnum = 10000;
string name = "RemoteClient";
SoapServerFormatterSinkProvider sinkProvider = new SoapServerFormatterSinkProvider();
sinkProvider.TypeFilterLevel = System.Runtime.Serialization.Formatters.TypeFilterLevel.Full;
ChannelServices.RegisterChannel(new HttpServerChannel(name, portnum, sinkProvider), false);
上記はHTTPプロトコルでSOAP形式でシリアライズ、クライアントが受け付けるポートは10000ということになりますので、TCP接続やBinaryシリアライズなどは適当に読み替えてください。英語ですが検索すれば、TCP接続やBinaryシリアライズの方が例はたくさん見つかります。
この例のようにクライアント側に書くコードですが、やっていることはサーバのそれ。サーバーがクライアントのdelegateを呼び出すという形をとってますが、その実はサーバーとクライアントが立場を入れ替えてソケット通信しているということなのでしょう。
Cook Computing の内容によると、この例外はdelegateだけでなく何らかの参照がサーバに渡され実体はクライアントだけにしかない場合に発生するとのこと。まぁ、冷静に考えてみればそうかな。
それまで問題なく動いていたプログラムが突然この例外を発生するようになり、以後ほぼ全てのサーバー→クライアント方向の通信が例外発生。どのタイミングでだめになるんですかねぇ。リース時間などと関係あるのだろうか、調べてる時間ない orz
[参考]
[2009/10/4 追記]構成ファイルだと以下の内容で動作しましたが、いまひとつ自信なし。MSのサイト行っても<channels>以下に具体的にどう書けばいいのか、ほとんど書いてないんですよねぇ・・・
<configuration>
<system.runtime.remoting>
<application name="Client">
<channels>
<channel ref="http" port="10000">
<clientProviders>
<formatter ref="soap" typeFilterLevel="Full" />
</clientProviders>
<serverProviders>
<formatter ref="soap" typeFilterLevel="Full" />
<provider ref="soap"/>
</serverProviders>
</channel>
</channels>
</application>
</system.runtime.remoting>
</configuration>
Comments