您的位置:首页 > 运维架构 > 网站架构

创建以Microsoft .NET Remoting为基础的分布式应用架构

2006-03-29 20:53 513 查看
引言

在论坛里经常看见有人问:使用.NETRemoting如何从服务器主动发出事件通知客户端?的确,初接触.NETRemoting的人多半会有这样的疑问,因为大部分的文章和书籍在介绍.NETRemoting时都只介绍了通道,对象,激活和生存周期等等概念,在谈到如何进行远程通信的时候,都只告诉读者如何从客户端激活一个服务器对象然后传递参数调用其方法。所以很多读者都不太清楚如何从服务器向客户端广播信息,甚至有很多人认为跟WEB服务器不能主动发送信息到浏览器一样,.NETRemoting同样也不能这么做,只能采用"客户端发出请求->服务器回复响应"这种简单的通讯模式,以至于在需要服务器对客户端广播信息时设计出两端都放上Server和Client对象的复杂架构,既麻烦又容易出错。

其实.NETRemoting远程处理完全支持事件驱动的编程和使用同步和异步委托的回调函数。在.NETRemoting中你可以方便的采用事件注册远程回调函数,并方便的利用这种机制将服务器端信息广播到客户端。下面将向读者详细介绍这种分布式多点广播应用程序架构的编写方法。

网络物理结构图

 

上面便是网络结构示意图,之所以说它是一个典型的分布式应用架构是因为基于这种网络结构十分常见,在证券交易,期货行情,视频会议,远程教学等许多方面都能派上用场。

架构设计

为了形象化抽象的概念,我们先来了解一下电视广播的工作流程,再结合我们的程序理解架构设计的主要思想。

电视广播的流程是由以下四个主要机构参与其中:

1.节目制作部门。负责制作电视节目。

2.转播间。负责安排节目制作部门提供的节目的广播方式。

3.电视塔。负责将电视信号转化为无线电波发送出去。

4.电视机。负责接受无线电信号并转换成可视的图象。

在我们的程序中也是由四个主要的对象组成,它们的名称和用途分别是:

1.Announcer:信息发送对象。负责发送原始信息,相当于电视节目制作部门。

2.InfoCenter:信息中心。负责管理信息广播机制。相当于转播间。

3.Server:服务器。管理传送通道,负责发送广播数据流。相当于电视塔。

4.Receiver:接受器。接受广播数据流,转换成我们可以理解的信息格式。相当于电视机。

对象结构如下图所示:

 

程序设计

首先我们来看一下信息中心InfoCenter对象的编写方法(InfoCenter.cs):

usingSystem;

usingSystem.Runtime.Remoting;

namespaceDistribution_Framework

{

//定义广播事件的参数类

[Serializable]

publicclassBroadcastEventArgs:EventArgs

{

privatestringmsg=null;

publicBroadcastEventArgs(stringmessage)

{

msg=message;

}

publicstringMessage

{

get

{

returnmsg;

}

}

}

publicdelegatevoidBroadcastEventHandler(objectsender,BroadcastEventArgssubmitArgs);

publicclassInfoCenter:MarshalByRefObject

{

publicInfoCenter()

{

Console.WriteLine("InfoCentercreated.");

}

publicoverrideobjectInitializeLifetimeService()

{

returnnull;

}

publiceventBroadcastEventHandlerBroadcaster;

publicvoidBroadcasting(stringmessage)

{

BroadcastEventArgse=newBroadcastEventArgs(message);


if(Broadcaster!=null)

{

Broadcaster(this,e);//发出事件

Console.WriteLine("Broadcast:"+e.Message);

}

}

}

}

要点说明:

publicdelegatevoidBroadcastEventHandler(objectsender,BroadcastEventArgssubmitArgs);

定义了一个事件处理委托及其参数格式。

publiceventBroadcastEventHandlerBroadcaster;

请注意,这一句定义了一个公共事件,需要接受广播信息的远程对象可以通过这个事件向InfoCenter注册使用BroadcastEventHandler委托的远程回调函数。这个机制有点类似有线受费电视,你如果需要收看电视台提供的电视节目请先来登记。

接下来看看Server对象的实现(Server.cs):

usingSystem;

usingSystem.Runtime.Remoting;


namespaceDistribution_Framework

{

classServer

{

publicstaticvoidMain(string[]Args)

{

RemotingConfiguration.Configure("Server.exe.config");

Console.WriteLine("Serverisrunning,PressEnterkeytoexit.");

Console.ReadLine();

}

}

}

呵呵,是不是跟电视塔一样简单?基本上除了"天线"就没别的了。:)

下面是它的配置文件(Server.exe.config):

<configuration>

<system.runtime.remoting>

<application>

<service>

<wellknown

mode="Singleton"

type="Distribution_Framework.InfoCenter,InfoCenter"

objectUri="Broadcast"

/>

</service>

<channels>

<channel

ref="http"

port="8080"

/>

</channels>

</application>

</system.runtime.remoting>

</configuration>

电视广播站已经架设好了,我们再来看看"电视机"是怎么做的(Receiver.cs):

usingSystem;

usingSystem.Runtime.Remoting;

usingSystem.Runtime.Remoting.Channels;

usingSystem.Runtime.Remoting.Channels.Http;


namespaceDistribution_Framework

{

classReceiver:MarshalByRefObject

{

InfoCenterinfoCenter;

publicReceiver()

{

}


publicoverrideobjectInitializeLifetimeService()

{

returnnull;

}


publicvoidRun()

{

RemotingConfiguration.Configure("Receiver.exe.config");

infoCenter=newInfoCenter();

//订阅信息

infoCenter.Broadcaster+=newBroadcastEventHandler(this.BroadcastReceiver);

Console.WriteLine("ReadytoRecieveMessage...");

Console.ReadLine();

//取消订阅

infoCenter.Broadcaster-=newBroadcastEventHandler(this.BroadcastReceiver);

}


publicvoidBroadcastReceiver(objectsender,BroadcastEventArgsargs)

{

Console.WriteLine("Received:"+args.Message);//打印接收信息

}


publicstaticvoidMain()

{

Receiverreceiver=newReceiver();

receiver.Run();

}

}

}

要点说明:

infoCenter.Broadcaster+=newBroadcastEventHandler(this.BroadcastReceiver);

还记得我们在InfoCenter中定义的那个Broadcaster事件吗?这里就是如何向它注册一个远程回调函数,相当于登记收看电视节目了。不想看了的话记得要向它取消登记哦,infoCenter.Broadcaster-=newBroadcastEventHandler(this.BroadcastReceiver);不然多收了你的钱可别耍赖。:)

publicvoidBroadcastReceiver(objectsender,BroadcastEventArgsargs)

{

Console.WriteLine("Received:"+args.Message);

}

这个就是被服务器端远程回调的函数。

另外要注意的是,这个客户对象也必须要从MarshalByRefObject继承,原因很简单,因为它相对于服务器来说也是一个需要进行序列化调用的远程对象。

下面是它的配置文件(Receiver.exe.config):

<configuration>

<system.runtime.remoting>

<application>

<client>

<wellknown

type="Distribution_Framework.InfoCenter,InfoCenter"

url="http://localhost:8080/Broadcast"

/>

</client>

<channels>

<channel

ref="http"

port="0"

/>

</channels>

</application>

</system.runtime.remoting>

</configuration>

请注意,port="0"表示由计算机自动选取一个最合适的端口。

我们现在电视机也有了,就差有人来送节目播放了,下面就是"电视节目制作部"的代码(Announcer.cs):

usingSystem;

usingSystem.Timers;

usingSystem.Runtime.Remoting;

usingSystem.Runtime.Remoting.Channels;

usingSystem.Runtime.Remoting.Channels.Http;



namespaceDistribution_Framework

{

classAnnouncer

{

InfoCenterinfoCenter;


publicstaticvoidMain(string[]Args)

{

Announcerannouncer=newAnnouncer();

announcer.Run();

Console.WriteLine("Theannouncerhasbeenstarted.");

Console.ReadLine();

}


publicvoidRun()

{

RemotingConfiguration.Configure("Announcer.exe.config");

infoCenter=newInfoCenter();

Timertimer=newTimer(1000);

timer.Elapsed+=newSystem.Timers.ElapsedEventHandler(this.timer_Elapsed);

timer.Enabled=true;

}


privatevoidtimer_Elapsed(objectsender,System.Timers.ElapsedEventArgse)

{

stringmsg="TheTimeis:"+DateTime.Now.ToString();

Console.WriteLine("SendMessage:"+msg);

infoCenter.Broadcasting(msg);

}

}

}

在这里,我们定义了一个定时器,每隔一秒种便向服务器发送一个计算机本地时间字符串信息,我们终于有可以收到的节目了,虽然是简单了点。另外,请注意,就象我们可以接收很多电视频道一样,发送者并没有规定只能有一个,事实上我们的确可以添加许多发送者,不过要注意线程之间的同步问题。

下面是它的配置文件(Announcer.exe.config):

<configuration>

<system.runtime.remoting>

<application>

<client>

<wellknown

type="Distribution_Framework.InfoCenter,InfoCenter"

url="http://localhost:8080/Broadcast"

/>

</client>

<channels>

<channel

ref="http"

port="0"

/>

</channels>

</application>

</system.runtime.remoting>

</configuration>

眼明的读者一下就看出来了,这个跟Receiver的配置文件一模一样,其实它们本来就都是客户端,配置文件当然是一样的。

最后,我们用下列命令将它们编译成可执行文件:

csc/t:libraryinfocenter.cs

csc/r:infocenter.dllserver.cs

csc/r:infocenter.dllreceiver.cs

csc/r:infocenter.dllannouncer.cs

请先运行Server.exe然后再运行Announcer.exe,最后你可以多打开几个Receiver,观察它们的工作情况。注意,如果你需要在不同的计算机上向别人演示这个程序的话,请将配置文件中的localhost改成相应的计算机名称或者是IP地址,而无须重新编译。

总结

使用.NET编程总是这么简单和有趣,在上例中,你几乎看不到什么关于"远程"的特殊代码,它非常接近于普通的程序调用,事实上,如果没有进行对RemotingConfiguration.Configure()的调用,你根本就不需要进行任何修改即可在单个应用程序域中编译和运行整个应用程序。

本文着重的是定义一个基于.NETRemoting的分布式远程应用架构的设计模式,其一部分设计思想来自于《设计模式》中的Observer模式,如果你对使用事件和委托来实现Observer模式的概念有些模糊的话,请参考拙文:利用C#的Delegate来改进Observer模式。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: