//—————————————————-
第1讲
//—————————————————-
Remoting 使用的技术
XML
SOAP
SerializableAttribute() 或实现ISerializable
//==Bin
FileStream fs = new FileStream("my.bin" , FileMode.Creat);
BinaryFormatter bf = new BinaryFormatter();
bf.Serialize(fs , myObj);
fs.Close();
//==Soap
FileStream fs = new FileStream("my.xml" , FileMode.Creat);
SoapFormatter formatter = new SoapFormatter();
formatter.Serialize(fs , myObj);
fs.Close();
//==XML
FileStream fs = new FileStream("my.xml" , FileMode.Creat);
System.Xml.Serialization.XmlSerializer xmlSer = new System.Xml.Serialization.XmlSerializer(typeof(MyType));
xmlSer.Serialize(fs , myObj);
fs.Close();
远程对象:
对象运行在远程(MarshalByRefObject)
传递对象副本(Serialize)
对象激活
服务器激活SAO(WellKnown)
Singleton
SingleCall
客户端激活
可保存会话状态
Channels
用于收发消息
TCP or Http, 也可自定义
开发remoting的步骤
创建远程对象
public class HelloServer: MarshalByRefObject
{
public
}
创建host程序, 或host在IIS中
注册通道(内置: TCP , HTTP)
注册服务器激活的远程对象, URL
运行宿主对象
建立客户端程序
注册通道(内置: TCP , HTTP)
根据URL得到对象代理
通过代理调用远程对象.
//===Sample : SampleRemoting
public class Client
{
public static void Main(string[] args)
{
//使用TCP通道得到远程对象
TcpChannel chan1 = new TcpChannel();
ChannelServices.RegisterChannel(chan1);
HelloServer obj1 = (HelloServer)Activator.GetObject(typeof(RemotingSamples.HelloServer),"tcp://localhost:8085/SayHello");
if (obj1 == null)
{
System.Console.WriteLine("Could not locate TCP server");
}
//使用HTTP通道得到远程对象
HttpChannel chan2 = new HttpChannel();
ChannelServices.RegisterChannel(chan2);
HelloServer obj2 = (HelloServer)Activator.GetObject(typeof(RemotingSamples.HelloServer), "http://localhost:8086/SayHello");
if (obj2 == null)
{
System.Console.WriteLine(
"Could not locate HTTP server");
}
Console.WriteLine( "Client1 TCP HelloMethod {0}", obj1.HelloMethod("Caveman1"));
Console.WriteLine("Client2 HTTP HelloMethod {0}", obj2.HelloMethod("Caveman2"));
Console.ReadLine();
}
/*
<configuration>
<system.runtime.remoting>
<application>
<client>
<wellknown type="HelloServer, General" url="http://localhost:8086/SayHello" />
</client>
<channels>
<channel ref="http" port="0"></channel>
</channels>
</application>
</system.runtime.remoting>
</configuration>
RemotingConfiguration.Configure(@"C:\Documents and Settings\RenMin\桌面\Remoting\Demo\02-SimpleRemoting\Client\client.exe.config");
HelloServer obj2 = new HelloServer();
*/
}
public class Server
{
public static int Main(string [] args)
{
TcpChannel chan1 = new TcpChannel(8085);
HttpChannel chan2 = new HttpChannel(8086);
//注册通道, server会开始监听该通道
ChannelServices.RegisterChannel(chan1);
ChannelServices.RegisterChannel(chan2);
RemotingConfiguration.RegisterWellKnownServiceType( typeof(HelloServer),
"SayHello" , //URL
WellKnownObjectMode.Singleton //对象类型
);
System.Console.WriteLine("Press Enter key to exit");
System.Console.ReadLine();
return 0;
}
}
//==Remote object
public class HelloServer : MarshalByRefObject
{
public HelloServer()
{
Console.WriteLine("HelloServer activated");
}
public String HelloMethod(String name)
{
Console.WriteLine( "Server Hello.HelloMethod : {0}", name);
return "Hi there " + name;
}
}
}
可传递的类型:
简单类型
可序列化的类型
自定义的类型[serializable]
在Client端直接使用User class
Singleton VS SingleCall
都是服务器激活(WellKnown)
Singleton :
在服务器端只实例化一次
每次调用都是同一实例.
可以维持状态
SingleCall
每次调用都实例化新的实例
Serialization vs MarshalByRefObject
Serialization
副本,不论Singleton还是SingleCall
MarshalByRefObject
通过proxy
Singleton记录更改, SingleCall无状态
判断一个obj是否是一个Proxy
RemotingServices.IsTransparentProxy()
//—————————————————-
第2讲
//—————————————————-
SAO 配置文件 wellknown
<configuration>
<system.runtime.remoting>
<application>
<service>
<wellknown mode="Singleton" objectUri="SayHello" type="RemotingSamples.HelloServer, General" />
</service>
<channels>
<channel port="8086" ref="http"/>
</channels>
</application>
</system.runtime.remoting>
</configuration>
<service>说明是server端
ref实际上是引用machine.config
%WINDIR%\Microsoft.NET\Framework\[version]\CONFIG
<channels>
<channel id="http" type=" "…/>
</channels>
客户端配置文件
<configuration>
<system.runtime.remoting>
<application>
<client>
<wellknown url="http://localhost:8086/SayHello" type="RemotingSamples.HelloServer, General" />
</client >
<channels>
<channel port="0" ref="http"/>
</channels>
</application>
</system.runtime.remoting>
</configuration>
<channel port="0" />client
不需要监听
–代码——————————————————-
Server.cs
public class Server
{
public static int Main(string [] args)
{
RemotingConfiguration.Configure(AppDomain.CurrentDomain.SetupInformation.ConfigurationFile);
//or RemotingConfiguration.Configure("Server.exe.config");
System.Console.WriteLine("Press Enter key to exit");
System.Console.ReadLine();
return 0;
}
}
Client.cs
public class Client
{
public static void Main(string[] args)
{
//使用HTTP通道得到远程对象
RemotingConfiguration.Configure(@"client.exe.config");
HelloServer obj2 = new HelloServer();
if (obj2 == null)
{
System.Console.WriteLine("Could not locate HTTP server");
}
Console.WriteLine( "Client2 HTTP HelloMethod {0}", obj2.HelloMethod("Caveman2"));
Console.ReadLine();
}
}
基于租约的对象生存期
可参考
使用.NET Remoting开发分布式应用——基于租约的生存期
http://terrylee.cnblogs.com/archive/2005/11/28/285809.html
微软的DCOM技术使用了Ping机制,在这种机制下,客户程序有规律的对服务程序发出Ping请求,
以通知服务程序自己仍旧活着,并通知服务程序自己需要使用哪个对象。
.NET Remoting使用的是基于租约的生存期机制,在租约期内,对象一直存活着,直到租借时间
结束,.NET Remoting使用Leasing程序完成了这项工作。
隐式续约
每次调用远程对象上的方法的时候自动进行。
显示的续约
ILease.Renew()
发起租约
ISponsor接口
ILease.Register()
租约的配置
租约配置 默认值(秒)
LeaseManagerPollTime 300
SponsorshipTimeout 120
RenewOnCallTime 120
InitialLeaseTime (轮讯时间) 10
//–如何得到当前的租约
HelloServer obj = (HelloServer)Activator.GetObject(typeof(RemotingSamples.HelloServer), "http://localhost:8086/SayHello");
ILease lease = (ILease)obj.GetLifetimeService();
if (lease != null)
{
Console.WriteLine("Lease Configuration:");
Console.WriteLine("InitialLeaseTime: " +
lease.InitialLeaseTime);
Console.WriteLine("RenewOnCallTime: " +
lease.RenewOnCallTime);
Console.WriteLine("SponsorshipTimeout: " +
lease.SponsorshipTimeout);
Console.WriteLine(lease.CurrentLeaseTime);
}
//–通过代码改变租约, 见 Helloserver.cs
// Overrides the lease settings for this object.
public override Object InitializeLifetimeService()
{
ILease lease = (ILease)base.InitializeLifetimeService();
// Normally, the initial lease time would be much longer.
// It is shortened here for demonstration purposes.
if (lease.CurrentState == LeaseState.Initial)
{
lease.InitialLeaseTime = TimeSpan.FromSeconds(3);
lease.SponsorshipTimeout = TimeSpan.FromSeconds(10);
lease.RenewOnCallTime = TimeSpan.FromSeconds(2);
}
return lease;
}
//–通过配置改变租约, 见 server的web.config
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<system.runtime.remoting>
<application>
….
<!–leaseManagerPollTime="7S"–>
<lifetime leaseTime="7M" sponsorshipTimeout="7M" renewOnCallTime="7M"/>
</application>
</system.runtime.remoting>
</configuration>
CAO客户端激活 activated
客户端激活的server端config文件
<application>
<service>
<activated type="ClientActivatedType, General"/>
</service>
</application>
client 端config文件
<application>
<client url="http://localhost:8080">
<activated type="ClientActivatedType, General"/>
</client>
</application>
优点客户端可以保存客户状态
例子为 04-CAOsDemo
客户端发起租约
例子为 05-SponserDemo
客户端发起租约的代码
public class MyClientSponsor : MarshalByRefObject, ISponsor
{
private DateTime lastRenewal;
public MyClientSponsor()
{
lastRenewal = DateTime.Now;
}
public TimeSpan Renewal(ILease lease)
{
Console.WriteLine("I’ve been asked to renew the lease.");
Console.WriteLine("Time since last renewal:" + (DateTime.Now - lastRenewal).ToString());
lastRenewal = DateTime.Now;
return TimeSpan.FromSeconds(20);
}
}
public class Client
{
public static void Main(string[] Args)
{
// Loads the configuration file.
RemotingConfiguration.Configure("client.exe.config");
ClientActivatedType CAObject = new ClientActivatedType();
ILease serverLease = (ILease)RemotingServices.GetLifetimeService(CAObject);
MyClientSponsor sponsor = new MyClientSponsor();
// Note: If you do not pass an initial time, the first request will
// be taken from the LeaseTime settings specified in the
// server.exe.config file.
serverLease.Register(sponsor);
……
}
}
//—————————————————-
第3讲
//—————————————————-
程序发布的模式: console, winform, winService, IIS
需要看源代码
//—————————————————-
第4讲
//—————————————————-
聊天程序