[Remoting] 十一:事件

在 Remoting 中使用 Event 主要是为了实现 CallBack 机制,让服务器在接收到某个 "消息" 时,主动调用某个或多个客户端的方法。

我们先看一个例子。
using System;
using System.Collections;
using System.Collections.Generic;
using System.Reflection;
using System.Runtime.Serialization.Formatters;
using System.Runtime.Serialization.Formatters.Binary;
using System.Runtime.Remoting;
using System.Runtime.Remoting.Channels;
using System.Runtime.Remoting.Channels.Tcp;

namespace Learn.Library.Remoting
{
  /// <summary>
  /// 委托类型
  /// </summary>
  public delegate void TestHandler();

  /// <summary>
  /// 远程类型
  /// </summary>
  public class Data : MarshalByRefObject
  {
    public TestHandler OnTest;

    public void Test()
    {
      Console.WriteLine("Test...(AppDomain:{0})", AppDomain.CurrentDomain.FriendlyName);
      if (OnTest != null) OnTest();
    }
  }

  public class RemotingTest2
  {
    /// <summary>
    /// 服务器端代码
    /// </summary>
    static void Server()
    {
      AppDomain server = AppDomain.CreateDomain("server");
      server.DoCallBack(delegate
      {
        BinaryServerFormatterSinkProvider bin = new BinaryServerFormatterSinkProvider();
        bin.TypeFilterLevel = TypeFilterLevel.Full;

        TcpServerChannel channel = new TcpServerChannel("server", 801, bin);
        ChannelServices.RegisterChannel(channel, false);

        RemotingConfiguration.RegisterWellKnownServiceType(typeof(Data), "data",
          WellKnownObjectMode.Singleton);
      });
    }

    /// <summary>
    /// 客户端代码
    /// </summary>
    static void Client()
    {
      TcpClientChannel channel = new TcpClientChannel();
      ChannelServices.RegisterChannel(channel, false);
      RemotingConfiguration.RegisterWellKnownClientType(typeof(Data), "tcp://localhost:801/data");

      Data data = new Data();
      data.OnTest += delegate
      {
        Console.WriteLine("OnTest...(AppDomain:{0})", AppDomain.CurrentDomain.FriendlyName);
      };
      data.Test();
    }

    static void Main()
    {
      Server();
      Client();
    }
  }
}

输出:
Test...(AppDomain:server)
OnTest...(AppDomain:server)

运行结果表明客户端事件方法 OnTest 被顺利执行。只不过结果有点问题,OnTest 是在服务器程序域内执行,这显然和我们设想服务器去通知客户端有所出入。这种方式实质上是将客户端委托方法一起序列化为消息传递到服务器端,然后在服务器应用程序域被执行,因此客户端是无法接收到所谓 "回调消息" 的。

要实现我们所需要的 Remoting Event,需要做如下步骤:

1. 采取所谓 Duplex 方式。也就是说在客户端和服务器同时启用 ServerChannel 和 ClientChannel,因此我们需要使用 HttpChannel 或 TcpChannel。
2. 客户端事件方法应该是一个继承自 MarshalByRefObject 类型的实例方法。因为服务器是通过创建客户端的 MBR SAO 对象来实现回调的。
3. 缺省情况下,Delegate 无法被序列化,因此我们需要将服务器的 Formatter.TypeFilterLevel 设置为 Full。

修改后的代码。
using System;
using System.Collections;
using System.Collections.Generic;
using System.Reflection;
using System.Runtime.Serialization.Formatters;
using System.Runtime.Serialization.Formatters.Binary;
using System.Runtime.Remoting;
using System.Runtime.Remoting.Channels;
using System.Runtime.Remoting.Channels.Tcp;

namespace Learn.Library.Remoting
{
  /// <summary>
  /// 委托类型
  /// </summary>
  public delegate void TestHandler();

  /// <summary>
  /// 远程类型
  /// </summary>
  public class Data : MarshalByRefObject
  {
    public TestHandler OnTest;

    public void Test()
    {
      Console.WriteLine("Test...(AppDomain:{0})", AppDomain.CurrentDomain.FriendlyName);
      if (OnTest != null) OnTest();
    }
  }

  /// <summary>
  /// 客户端远程类型
  /// </summary>
  public class ClientData : MarshalByRefObject
  {
    public void OnTestMethod()
    {
      Console.WriteLine("Test...(AppDomain:{0})", AppDomain.CurrentDomain.FriendlyName);
    }
  }

  public class RemotingTest2
  {
    /// <summary>
    /// 服务器端代码
    /// </summary>
    static void Server()
    {
      AppDomain server = AppDomain.CreateDomain("server");
      server.DoCallBack(delegate
      {
        BinaryClientFormatterSinkProvider cbin = new BinaryClientFormatterSinkProvider();
        BinaryServerFormatterSinkProvider sbin = new BinaryServerFormatterSinkProvider();
        sbin.TypeFilterLevel = TypeFilterLevel.Full;

        Hashtable properties = new Hashtable();
        properties["port"] = 801;

        TcpChannel channel = new TcpChannel(properties, cbin, sbin);
        ChannelServices.RegisterChannel(channel, false);

        RemotingConfiguration.RegisterWellKnownServiceType(typeof(Data), "data",
          WellKnownObjectMode.Singleton);
      });
    }

    /// <summary>
    /// 客户端代码
    /// </summary>
    static void Client()
    {
      TcpChannel channel = new TcpChannel(802);
      ChannelServices.RegisterChannel(channel, false);
      RemotingConfiguration.RegisterWellKnownClientType(typeof(Data), "tcp://localhost:801/data");

      Data data = new Data();
      data.OnTest += new ClientData().OnTestMethod;
      data.Test();
    }

    static void Main()
    {
      Server();
      Client();
    }
  }
}

输出:
Test...(AppDomain:server)
Test...(AppDomain:Test.exe)  
 

转载于:https://www.cnblogs.com/leonardleonard/archive/2007/03/19/1928402.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值