[Remoting] 九:动态发布
使用动态发布有什么好处?
1. 避开 SAO 只能使用默认构造方法的限制。
2. 自主管理 SAO 的载入、卸载,以及其 URI。
RemotingServices
通过使用类 RemotingServices 提供的方法,我们可以很轻松实现这些目标。
ObjRef 是远程对象的可序列化表示,用于跨应用程序域边界传输对象引用。为对象创建 ObjRef 称为封送。可以通过信道将 ObjRef 传输到另一个应用程序域(可能在另一个进程或计算机上)。达到其他应用程序域后,需立即分析 ObjRef,以便为该对象创建一个代理(通常连接到实际的对象)。此操作称为拆收处理 (Unmarshaling)。在拆收处理过程中,分析 ObjRef 以提取远程对象的方法信息,并创建透明代理和 RealProxy 对象。在透明代理注册到公共语言运行库之前,将已分析的 ObjRef 的内容添加到透明代理中。
ObjRef 包含:描述所封送对象的 Type 和类的信息,唯一标识特定对象实例的 URI,以及有关如何到达对象所在的远程处理分支的相关通信信息。
动态发布示例
1. 避开 SAO 只能使用默认构造方法的限制。
2. 自主管理 SAO 的载入、卸载,以及其 URI。
RemotingServices
通过使用类 RemotingServices 提供的方法,我们可以很轻松实现这些目标。
- Marshal: 用于将 MarshalByRefObject 转换为 ObjRef 类的实例。
- Connect:客户端可以用该方法创建远程代理对象的实例。
- Disconnect:断开服务器远程对象与信道的连接。客户端代理在断开后调用任何方法都会触发 RemotingException。
- Unmarshal:接受 ObjRef 并从它创建一个客户端代理对象。这个方法很少被使用,因为多数情况下我们并不会直接将 ObjRef 显示传递给客户端,而是交由 Remoting 基础结构来处理。
ObjRef 是远程对象的可序列化表示,用于跨应用程序域边界传输对象引用。为对象创建 ObjRef 称为封送。可以通过信道将 ObjRef 传输到另一个应用程序域(可能在另一个进程或计算机上)。达到其他应用程序域后,需立即分析 ObjRef,以便为该对象创建一个代理(通常连接到实际的对象)。此操作称为拆收处理 (Unmarshaling)。在拆收处理过程中,分析 ObjRef 以提取远程对象的方法信息,并创建透明代理和 RealProxy 对象。在透明代理注册到公共语言运行库之前,将已分析的 ObjRef 的内容添加到透明代理中。
ObjRef 包含:描述所封送对象的 Type 和类的信息,唯一标识特定对象实例的 URI,以及有关如何到达对象所在的远程处理分支的相关通信信息。
动态发布示例
using System;
using System.Collections;
using System.Collections.Generic;
using System.Reflection;
using System.Threading;
using System.IO;
using System.Security.Permissions;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters;
using System.Runtime.Serialization.Formatters.Binary;
using System.Runtime.CompilerServices;
using System.Runtime.Remoting;
using System.Runtime.Remoting.Channels;
using System.Runtime.Remoting.Channels.Tcp;
using System.Runtime.Remoting.Messaging;
using System.Runtime.Remoting.Lifetime;
using System.Runtime.Remoting.Services;
namespace Learn.Library.Remoting
{
/// <summary>
/// 远程类型
/// </summary>
public class Data : MarshalByRefObject
{
public void Test()
{
Console.WriteLine("Test AppDomain:{0}", AppDomain.CurrentDomain.FriendlyName);
}
public void Disconnect()
{
// 断开连接
RemotingServices.Disconnect(this);
}
}
public class RemotingTest2
{
/// <summary>
/// 服务器端代码
/// </summary>
static void Server()
{
AppDomain server = AppDomain.CreateDomain("server");
server.DoCallBack(delegate
{
TcpServerChannel channel = new TcpServerChannel(801);
ChannelServices.RegisterChannel(channel, false);
// 创建远程对象实例,当然也可以使用非默认构造方法。
// 此方式类似于 SAO.Singleton 。
Data data = new Data();
// 封送远程对象。
ObjRef objRef = RemotingServices.Marshal(data, "data");
});
}
/// <summary>
/// 客户端代码
/// </summary>
static void Client()
{
TcpClientChannel channel = new TcpClientChannel();
ChannelServices.RegisterChannel(channel, false);
// 连接服务器,并创建代理实例。
Data data = (Data)RemotingServices.Connect(typeof(Data), "tcp://localhost:801/data");
// 调用远程对象方法。
data.Test();
// 调用远程对象方法,断开连接。
data.Disconnect();
// 再次调用远程对象方法时,因连接已断开,将抛出 RemotingException。
data.Test();
}
static void Main()
{
Server();
Client();
}
}
}
using System.Collections;
using System.Collections.Generic;
using System.Reflection;
using System.Threading;
using System.IO;
using System.Security.Permissions;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters;
using System.Runtime.Serialization.Formatters.Binary;
using System.Runtime.CompilerServices;
using System.Runtime.Remoting;
using System.Runtime.Remoting.Channels;
using System.Runtime.Remoting.Channels.Tcp;
using System.Runtime.Remoting.Messaging;
using System.Runtime.Remoting.Lifetime;
using System.Runtime.Remoting.Services;
namespace Learn.Library.Remoting
{
/// <summary>
/// 远程类型
/// </summary>
public class Data : MarshalByRefObject
{
public void Test()
{
Console.WriteLine("Test AppDomain:{0}", AppDomain.CurrentDomain.FriendlyName);
}
public void Disconnect()
{
// 断开连接
RemotingServices.Disconnect(this);
}
}
public class RemotingTest2
{
/// <summary>
/// 服务器端代码
/// </summary>
static void Server()
{
AppDomain server = AppDomain.CreateDomain("server");
server.DoCallBack(delegate
{
TcpServerChannel channel = new TcpServerChannel(801);
ChannelServices.RegisterChannel(channel, false);
// 创建远程对象实例,当然也可以使用非默认构造方法。
// 此方式类似于 SAO.Singleton 。
Data data = new Data();
// 封送远程对象。
ObjRef objRef = RemotingServices.Marshal(data, "data");
});
}
/// <summary>
/// 客户端代码
/// </summary>
static void Client()
{
TcpClientChannel channel = new TcpClientChannel();
ChannelServices.RegisterChannel(channel, false);
// 连接服务器,并创建代理实例。
Data data = (Data)RemotingServices.Connect(typeof(Data), "tcp://localhost:801/data");
// 调用远程对象方法。
data.Test();
// 调用远程对象方法,断开连接。
data.Disconnect();
// 再次调用远程对象方法时,因连接已断开,将抛出 RemotingException。
data.Test();
}
static void Main()
{
Server();
Client();
}
}
}