今天闲来无事,就把remoting研究了下,之前也接触过,对remoting也有一点点的了解,只是没怎么去深究过,今天我通过我对remoting的一点点理解,给刚接触remoting的学友们介绍下remoting到底是什么,怎么去用,在什么场合去用。
remoting的工作原理:就是服务端向客户端发送一个进程编号,一个程序域编号,以确定对象的位置。一般用在2个或2个以上的进程中,也就是所谓的跨程序来执行项目,类型webservice。
接下来,我就把我做得一个简单示例讲解下,如何去实现remoting。这个示例主要实现的是"当前时间自动更新"。
先看看效果图:
整个程序,我新建了2个项目,一个是服务端项目RemotingDemo,另一个是客户端项目RemotingCustom。
我们第一步先在服务端新建一个Message类,因为这个类起着关键性的作用。
代码中用的是委托和事件,相信大家都能理解。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace RemotingDemo
{
//将定义的message类继承MarshalByRefObject,主要是因为继承此类的对象可以跨越应用程序域边界被引用,甚至被远程引用。远程调用时,将产生一个远程对象在本地的透明代理,通过此代理来进行远程调用。
public class Message:MarshalByRefObject
{
public delegate void DeleHanlder(string time);
public static event DeleHanlder getCurrentTime;
public void CurrentTime(string time)
{
if (getCurrentTime != null)
{
getCurrentTime(time);
}
}
}
}
好了,第一步已经完成。
接下来我们先部署服务端
服务端:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Runtime.Remoting.Channels.Http;
using System.Runtime.Remoting.Channels;
using System.Runtime.Remoting;
using System.Threading;
namespace RemotingDemo
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
/// <summary>
/// 开启服务端
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void button1_Click(object sender, EventArgs e)
{
//首先要先添加System.Runtime.Remoting的引用,不然不能使用Remoting相关的指令
HttpChannel channel = new HttpChannel(3000);//给3000端口指定通道
ChannelServices.RegisterChannel(channel,false);//注册通道
RemotingConfiguration.RegisterWellKnownServiceType(typeof(RemotingDemo.Message), "Message", WellKnownObjectMode.SingleCall);//激活通道,通常激活通道的方式有2种:SingleCall和Singleton;前者是每个传入的消息是由新的对象提供服务,后者则是每个传入的消息由同一个对象提供服务,两者是有差别的。比如:我实现一个i不断自加,如果我用前者,则每次返回的都是从头开始的数,如果是用后者,则i不断的自加,区别就在这里
button1.Enabled = false;
RemotingDemo.Message.getCurrentTime += new Message.DeleHanlder(Message_getCurrentTime);//服务端通道已经激活,我们这时就可以订阅事件来实现相应操作的效果
}
void Message_getCurrentTime(string time)
{ //下面这段代码对于多线程不太了解的人来说,可能不好理解,这里我就先简单的阐述下,如果不使用invoke的话,会报子线程不能直接访问主线程UI的异常,简单点来说就是不具备使用它的权限,需要使用权限。还有"=>"这个写法是Lambda表达式,大家不了解的可以去网上查看,我就不再复述了
if (this.InvokeRequired)
{
this.Invoke(new MethodInvoker(() =>
{
textBox1.Text = time;
}));
}
else
{
textBox1.Text = time;
}
}
}
}
客户端:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Runtime.Remoting.Channels;
using System.Runtime.Remoting;
using System.Runtime.Remoting.Channels.Http;
using System.Threading;
namespace RemotingCustom
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button2_Click(object sender, EventArgs e)
{
HttpChannel channel = new HttpChannel();//不需要指定端口
ChannelServices.RegisterChannel(channel, false);//注册通道
RemotingConfiguration.RegisterWellKnownClientType(typeof(RemotingDemo.Message), "http://localhost:3000/Message");//客户端指定的url,以便于发送信息
RemotingDemo.Message msg = new RemotingDemo.Message();
while (true)
{
msg.CurrentTime(DateTime.Now.ToString("HH:mm:ss"));
Thread.Sleep(1000);
}
}
}
}
正个流程就是我们开启服务器,服务端已订阅事件,等待一个事件的触发,这时刚好客户端启动后,触发了这个事件,来完成两个进程间的合作关系。好了,如果大家对remoting感兴趣的话,可以深入的去理解。
还有,我要提一下的是,或许有人会不知道怎么同时启动2个项目,这里呢,我们先将服务端项目设为启动项目,启动服务端后,我们右击客户端项目=>调试=>启动新实例,这时客户端就启动了。