.NET Remoting 体系结构 之 信道的功能和配置 (二)
格式化程序
.NET Framework 提供了两个格式化程序类,即:
● System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
● System.Runtime.Serialization.Formatters.Soap.SoapFormatter 通过格式化程序接收器对象和格式化程序接收器提供程序,可以把格式化程序和信道联系起来。 这两个格式化程序类都实现 System.Runtime.Remoting.Messaging.IRemotingFormatter 接口,该接 口定义 Serialize()方法和 Deserialize()方法,以便在信道之间来回传输数据。 格式化程序也是“可插入的”。在编写自定义格式化程序类时,必须把实例与要使用的信道联系 起来,这项工作使用格式化程序接收器和格式化程序接收器提供程序就可以完成。例如,在创建前 面介绍的信道时,格式化程序接收器提供程序 SoapServerFormatterSinkProvider 可以作为参数传递。格 式化程序接收器提供程序为服务器实现 IServerChannelSinkProvider 接口,为客户端实现 IClientChannelSinkProvider 接口。这两个接口都定义 CreateSink()方法,这个方法必须返回格式化程 序接收器。SoapServerFormatterSinkProvider 返回 SoapServerFormatterSink 类的一个实例。 在客户端,SoapClientFormatterSink 类使用 SoapFormatter 类的 SyncProcessMessage()方法和 AsyncProcessMessage()方法,序列化消息。而 SoapServerFormatterSink 类使用 SoapFormatter 类反序 列化消息。 所有这些接收器和提供程序类都可以扩展,并可以被自定义实现方式替代。
ChannelServices 和RemotingConfiguration
ChannelServices 实用程序类用于把信道注册到.NET Remoting 运行库中。此外,也可以使用这 个类访问所有已注册的信道。因为在这里信道是隐式创建的,所以在使用配置文 件配置信道时,ChannelServices 类极其有用。
使用静态方法 ChannelServices.RegisterChannel()可以注册信道。这个方法的第一个参数需要该信 道,把第二个参数设置为 true,可以验证安全性对于信道是否可用。因为 HttpChannel 类没有安全支 持,所以把对应的检查设置为 false。下面是注册 HTTP、TCP 和IPC 信道的服务器代码:
var tcpChannel = new TcpChannel(8086); var httpChannel = new HttpChannel(8085); var ipcChannel = new IpcChannel("myIPCPort"); ChannelServices.RegisterChannel(tcpChannel, true); ChannelServices.RegisterChannel(httpChannel, false); ChannelServices.RegisterChannel(ipcChannel, true);
ChannelServices 实用程序类可以用于分配同步消息和异步消息,以及注销指定信道。 RegisteredChannels 属性返回一个 IChannel 数组,数组中的元素是已注册的所有信道。此外,还可以 使用 GetChannel()方法根据名称获取指定的信道。使用 ChannelServices 类,可以编写自定义管理实 用程序,用于管理信道。下面的小示例阐明了如何阻止服务器信道侦听所传入的请求:
1 HttpServerChannel channel = (HttpServerChannel)ChannelServices.GetChannel("http"); 2 channel.StopListening(null);
RemotingConfiguration 类是另一个.NET Remoting 实用程序类。在服务器端,这个类用于为服务器 激活的对象注册远程对象类型,把远程对象编组到已编组的对象引用类 ObjRef 中。ObjRef 是在网络 上发送的对象的可序列化表示。在客户端,为了从对象引用中创建代理,需要使用 RemotingServices 类打乱远程对象。
1. 知名对象的服务器
下面的服务器端代码把知名的远程对象类型注册为 RemotingServices:
1 RemotingConfiguration.RegisterWellKnownServiceType( typeof(Hello), // Type 2 "Hi", // URI 3 WellKnownObjectMode.SingleCall); // Mode
RegisterWellKnownServiceType()方法的第一个参数是 typeof(Hello),它指定远程对象的类型。第 二个参数 Hi 是远程对象的 URI,客户端访问远程对象时要使用这个 URI。后一个参数是远程对象 的模式。模式可以是 WellKnownObjectMode 枚举的一个值:SingleCall 或 Singleton。
● SingleCall 意味着对象不保存状态。每一次调用远程对象时,都会创建一个新的实例。使用 RemotingConfiguration.RegisterWellKnownServiceType()方法和 WellKnownObjectMode.SingleCall 参数,可以从服务器中创建 SingleCall 对象。因为不需要为数千个客户端保存资源,因此,这 种模式在服务器上非常高效。
● 使用 singleton,服务器的所有客户端都可以共享对象。一般情况下,如果要在所有的客户端 之间共享一些数据,则可以使用这种对象类型。对于只读数据这是毫无问题的,但是,对 于可读写的数据,就必须考虑数据锁定问题和可伸缩性。使用 RemotingConfiguration. RegisterWellKnownServiceType()方法和 WellKnownObjectMode. Singleton 参数,服务器可以 创建单一对象。必须考虑单一对象所使用资源的锁定问题。在客户端并发地访问单一对象 时,必须确保数据不能被损坏,还必须检查锁定是否足够有效,以便实现必要的可伸缩性。
2. 客户端激活的对象的服务器
不调用 RemotingConfiguration.RegisterWellKnownType()方法,而必须调用 Remoting Configuration. RegisterActivatedServiceType()方法。使用这个方法时,只指定类型,不指定 URI。原因是,对于客 户端激活的对象,客户端可以使用同一个 URI 对不同的对象类型进行实例化。所有客户激活的对象 的URI 必须使用 RemotingConfiguration.ApplicationName 定义:
RemotingConfiguration.ApplicationName = "HelloServer";
RemotingConfiguration.RegisterActivatedServiceType(typeof(Hello));