.NET Remoting可以用来实现远程访问,通过通道(channel)实现两个应用程序域之间对象的通信。Remoting通道有Tcp和Http两种,这里以Tcp为例,Http可以参考原帖:http://blog.csdn.net/doubleyou/article/details/2059351
先上一个入门练手例子:
Step1:创建类库(DLL)工程RemotingObjects,类Person代码如下:
<strong>using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace RemotingObjects
{
public interface IPerson
{
String getName(String name);
}
public class Person : MarshalByRefObject, IPerson
{
public Person()
{
Console.WriteLine("[Person]:Remoting Object 'Person' is activated.");
}
public String getName(String name)
{
return name;
}
}
}</strong>
Step2:创建控制台工程RemotingServer(添加项目引用RemotingObjects和System.Runtime.Remoting),类Server代码如下:
<strong>using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Runtime.Remoting;
using System.Runtime.Remoting.Channels;
using System.Runtime.Remoting.Channels.Tcp;
namespace RemotingServer
{
class Server
{
static void Main(string[] args)
{
TcpChannel channel = new TcpChannel(8089);
ChannelServices.RegisterChannel(channel, false);
RemotingConfiguration.RegisterWellKnownServiceType(typeof(RemotingObjects.Person), "RemotingPersonService", WellKnownObjectMode.SingleCall);
System.Console.WriteLine("Server:Press Enter key to exit");
System.Console.ReadLine();
}
}
}</strong>
Step3:创建控制台工程RemotingClient(添加项目引用RemotingObjects及必要类库),类Client代码如下:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Runtime.Remoting.Channels;
using System.Runtime.Remoting.Channels.Tcp;
using RemotingObjects;
namespace RemotingClient
{
class Client
{
static void Main(string[] args)
{
TcpChannel channel = new TcpChannel();
ChannelServices.RegisterChannel(channel, false);
IPerson obj = (IPerson)Activator.GetObject(typeof(RemotingObjects.IPerson), "tcp://localhost:8089/RemotingPersonService");
if (obj == null)
{
Console.WriteLine("Couldn't create Remoting Object 'Person'.");
}
Console.WriteLine("Please enter your name:");
string name = Console.ReadLine();
try
{
Console.WriteLine(obj.getName(name));
}
catch (System.Net.Sockets.SocketException e)
{
Console.WriteLine(e.ToString());
}
Console.ReadLine();
}
}
}
OK!例子上手后就学习具体的内容:
服务器端:
1、注册通道
tcp通道和http通道除了性能和序列号格式不同外,实现方式是完全相同的。在实例化通道对象时,将端口号作为参数传递。然后再调用静态方法RegisterChannel()来注册该通道对象即可。
A.项目右键添加引用"System.Runtime.Remoting",
B.添加一下名称空间:
using System.Runtime.Remoting.Channels;
using System.Runtime.Remoting.Channels.Http;
/ /using System.Runtime.Remoting.Channels.Tcp;
C. 代码如下:
HttpChannel channel = new HttpChannel(8080);
//TcpChannel channel = new TcpChannel(8080);
ChannelServices.RegisterChannel(channel);
2、注册远程对象
注册了通道后,要能激活远程对象,必须在通道中注册该对象。根据激活模式的不同,注册对象的方法也不同
(1) SingleTon模式 | 对于WellKnown对象,可以通过静态方法RemotingConfiguration.RegisterWellKnownServiceType ()来实现:RemotingConfiguration.RegisterWellKnownServiceType( typeof(ServerRemoteObject.ServerObject), "ServiceMessage",WellKnownObjectMode.SingleTon); |
(2)SingleCall模式 | RemotingConfiguration.RegisterWellKnownServiceType( typeof(ServerRemoteObject.ServerObject), "ServiceMessage",WellKnownObjectMode.SingleCall); 注册对象的方法基本上和SingleTon模式相同,只需要将枚举参数WellKnownObjectMode改为SingleCall就可以了。 |
(3)客户端激活模式 | RemotingConfiguration.ApplicationName = "ServiceMessage"; |
3、注销通道
如果要关闭Remoting的服务,则需要注销通道,也可以关闭对通道的监听。在Remoting中当我们注册通道的时候,就自动开启了通道的监听。而如果关闭了对通道的监听,则该通道就无法接受客户端的请求,但通道仍然存在,如果你想再一次注册该通道,会抛出异常。
//获得当前已注册的通道;
IChannel[] channels = ChannelServices.RegisteredChannels;
//关闭指定名为MyTcp的通道;
foreach (IChannel eachChannel in channels)
{
if (eachChannel.ChannelName == "MyTcp")
{
TcpChannel tcpChannel = (TcpChannel)eachChannel;
//关闭监听;
tcpChannel.StopListening(null);
//注销通道;
ChannelServices.UnregisterChannel(tcpChannel);
}
}
代码中,RegisterdChannel属性获得的是当前已注册的通道。在Remoting中,是允许同时注册多个通道的,这一点会在后面说明。
客户端:
1、注册通道
TcpChannel channel = new TcpChannel();
ChannelServices.RegisterChannel(channel);
注意在客户端实例化通道时,是调用的默认构造函数,即没有传递端口号。事实上,这个端口号是缺一不可的,只不过它的指定被放在后面作为了Uri的一部分。
2、注册远程对象
2、获得远程对象。
与服务器端相同,不同的激活模式决定了客户端的实现方式也将不同。不过这个区别仅仅是WellKnown激活模式和客户端激活模式之间的区别,而对于SingleTon和SingleCall模式,客户端的实现完全相同。
(1) WellKnown激活模式
要获得服务器端的知名远程对象,可通过Activator进程的GetObject()方法来获得:
ServerRemoteObject.ServerObject serverObj = (ServerRemoteObject.ServerObject)Activator.GetObject(
typeof(ServerRemoteObject.ServerObject), "tcp://localhost:8080/ServiceMessage");
首先以WellKnown模式激活,客户端获得对象的方法是使用GetObject()。其中参数第一个是远程对象的类型。第二个参数就是服务器端的uri。如果是http通道,自然是用http://localhost:8080/ServiceMessage了。因为我是用本地机,所以这里是localhost,你可以用具体的服务器IP地址来代替它。端口必须和服务器端的端口一致。后面则是服务器定义的远程对象服务名,即ApplicationName属性的内容。
(2) 客户端激活模式
如前所述,WellKnown模式在客户端创建对象时,只能调用默认的构造函数,而客户端激活模式则可以通过自定义的构造函数来创建远程对象。
客户端激活模式有两种方法:
1) 调用RemotingConfiguration的静态方法RegisterActivatedClientType()。这个方法返回值为Void,它只是将远程对象注册在客户端而已。具体的实例化还需要调用对象类的构造函数。
RemotingConfiguration.RegisterActivatedClientType(
typeof(ServerRemoteObject.ServerObject),
"tcp://localhost:8080/ServiceMessage");
ServerRemoteObject.ServerObject serverObj = new ServerRemoteObject.ServerObject();
2) 调用进程Activator的CreateInstance()方法。这个方法将创建方法参数指定类型的类对象。它与前面的GetObject()不同的 是,它要在客户端调用构造函数,而GetObject()只是获得对象,而创建实例是在服务器端完成的。CreateInstance()方法有很多个重 载,我着重说一下其中常用的两个。
a、 public static object CreateInstance(Type type, object[] args, object[] activationAttributes);
b、public static ObjectHandle CreateInstance(string assemblyName, string typeName, object[] activationAttribute);
详细参数说明见表后AAA
说明:要使用UrlAttribute,还需要在命名空间中添加:using System.Runtime.Remoting.Activation;
另外,原博客还有很多Remoting补充,这里只说明一点,如何监听多通道:
直接上源码:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Runtime.Remoting;
using System.Runtime.Remoting.Channels;
using System.Runtime.Remoting.Channels.Tcp;
using System.Collections;
namespace RemotingServer
{
class Server
{
static void Main(string[] args)
{
IDictionary tcpProp = new Hashtable();
tcpProp["name"] = "tcp9099";
tcpProp["port"] = 9099;
IChannel channel = new TcpChannel(tcpProp, new BinaryClientFormatterSinkProvider(), new BinaryServerFormatterSinkProvider());
IDictionary tcpProp1 = new Hashtable();
tcpProp1["name"] = "tcp9199";
tcpProp1["port"] = 9199;
IChannel channel1 = new TcpChannel(tcpProp1, new BinaryClientFormatterSinkProvider(), new BinaryServerFormatterSinkProvider());
ChannelServices.RegisterChannel(channel);
//TcpChannel channel = new TcpChannel(8089);
//ChannelServices.RegisterChannel(channel, false);
RemotingConfiguration.RegisterWellKnownServiceType(typeof(RemotingObjects.Person), "RemotingPersonService", WellKnownObjectMode.SingleCall);
System.Console.WriteLine("Server:Press Enter key to exit");
System.Console.ReadLine();
}
}
}