先提供实例下载地址
http://download.youkuaiyun.com/source/3098005(运行此实例请开启sqlserver服务)
简单介绍
.net remoting是.net在RPC分布式应用的技术,首先,客户端通过 remoting,访问通道以获得服务端对象,再通过代理解析为客户端对象,通过通道来实现远程对象的调用,在这里,客户端调用的是一个可序列化的对象及其方法,而不是一个简单的方法。
原理:
远程对象代码可以运行在服务器上,然后客户端再通过 remoting中定义的通道连接服务器,获得该服务对象并通过序列化在客户端运行。通道即服务端与客户端之间通过IP地址和端口号建立的传输序列化对象的途径。在 remoting 中,对于要传递的对象,开发人员除了需要了解通道的类型、地址和端口号之外,无需再了解数据包的格式。
TCP通道:
remoting 的通道主要有两种:tcp 和 http。在.net 中,system.runtime.remoting.channel 中
定义了 ichannel 接口。ichannel 接口包括了 tcpchannel 通道类型和 http 通道类型。它们分别对应 remoting 通道的这两种类型。我用的就是TCP通道。这里不介绍HTTP通道了。
tcpchannel 类型放在名字空间 system.runtime.remoting.channel.tcp 中。tcp 通道提供了基
于 socket 的传输工具, 使用 tcp 协议来跨越 remoting 边界传输序列化的消息流。 tcpchannel类型默认使用二进制格式序列化消息对象,因此它具有更高的传输性能。
激活可序列化的对象:
在访问远程类型的一个对象实例之前,必须通过一个名为 activation 的进程创建它并进行初
始化。这种客户端通过通道来创建远程对象,称为对象的激活。在 remoting 中,远程对象
的激活分为两大类:服务器端激活和客户端激活。
.net remoting 把服务器端激活又分为 singleton 模式和singlecall 模式两种。这里我使用的是singlecall模式。singlecall 是一种无状态模式。一旦设置为 singlecall 模式,则当客户端调用远程对象的方法时,remoting 会为每一个客户端建立一个远程对象实例由于 remoting 传递的对象是以引用的方式,因此所传递的远程对象类必须继承marshalbyrefobject。
这里再介绍一下singleton 模式:此为有状态模式。如果设置为 singleton 激活方式,则 remoting 将为所有客户端建立同一个对象实例。当对象处于活动状态时,singleton 实例会处理所有后来的客户端访问请求,而不管它们是同一个客户端,还是其他客户端。singleton 实例将在方法调用中一直维持其状态。
因此,有了可以传输的对象,有了传输的通道,那么客户端就可以利用通道调用服务端的对象了。
根据实验的具体应用
题目:假设学生选课数据库由三张表构成:学生表S(sno,sname,…),课程表C(cno,cname,cteacher,…),学生选课表SC(sno,cno),写程序统计有超过三门课不及格的学生人数。要求利用RPC技术,将查询过程放在服务端,客户端远程调用服务端的查询方法,该方法返回查询结果。
结果如下所示:

先定义可序列化的对象:(这个对象在客户端和服务端都必须定义,但客户端无需详细定义,因为客户端只需要它的引用而已,而服务端要定义其具体的实现)
[Serializable]//对象可序列化必须定义为该熟悉
public class RPCDEMO : System.MarshalByRefObject
//采用singelcal模式必须继承MarshalByRefObject对象
{
public RPCDEMO()
{
}
public string caculate(string name)
{
//具体的实现过程在服务端进行定义,客户端可以不定义
return "统计有超过三门课不及格的学生人数为" +count+"人";
}
}
客户端client:
class Client
{
static void Main(string[] args)
{
ChannelServices.RegisterChannel(new TcpClientChannel(), false);
//注册TCP通道
RPCDEMO obj = (RPCDEMO)Activator.GetObject(typeof(RPCDEMO), "tcp://localhost:8888/caculate");//激活远程服务对象RPCDEMO
if (obj == null)
{
Console.WriteLine("False to Link Server.");
return;
}
while (1 == 1)
{
Console.WriteLine(obj.caculate(System.Console.ReadLine()));
//每读一次命令行,调用一次远程对象的caculate方法
}
System.Console.ReadLine();
}
}
服务端server
class Server
{
static void Main(string[] args)
{
//服务端侦听端口
TcpServerChannel channel = new TcpServerChannel(8888);
//注册通道
ChannelServices.RegisterChannel(channel, false);
//定义对象激活方式
RemotingConfiguration.RegisterWellKnownServiceType(typeof(RPCDEMO), "caculate", WellKnownObjectMode.SingleCall);
System.Console.WriteLine("Press Any Key to Exit ! ");
System.Console.ReadLine();
}
}