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

摘要:
在论坛中,人们经常问:我如何使用从服务器向客户端发送事件通知。NET远程处理?实际上,NETRemoting完全支持使用同步和异步委托的事件驱动编程和回调函数。在NET Remoting中,您可以方便地使用事件注册远程回调函数,并使用此机制将信息从服务器广播到客户端(=空){broadcast;//发出事件Console.WriteLine;//事件控制台;}要点:publicdelegatevoidBroadcastEventHandler;定义事件处理委托及其参数格式。publiceventBroadcastEventHandlerBroadcaster;请注意,这句话定义了一个公共事件,需要接收广播信息的远程对象可以通过该事件向信息中心注册BroadcastEventHandler委托的远程回调函数。
在论坛里经常看见有人问:使用.NET Remoting如何从服务器主动发出事件通知客户端?的确,初接触.NET Remoting的人多半会有这样的疑问,因为大部分的文章和书籍在介绍.NET Remoting时都只介绍了通道,对象,激活和生存周期等等概念,在谈到如何进行远程通信的时候,都只告诉读者如何从客户端激活一个服务器对象然后传递参数调用其方法。所以很多读者都不太清楚如何从服务器向客户端广播信息,甚至有很多人认为跟WEB服务器不能主动发送信息到浏览器一样,.NET Remoting同样也不能这么做,只能采用"客户端发出请求->服务器回复响应"这种简单的通讯模式,以至于在需要服务器对客户端广播信息时设计出两端都放上Server和Client对象的复杂架构,既麻烦又容易出错。
其实.NET Remoting远程处理完全支持事件驱动的编程和使用同步和异步委托的回调函数。在.NET Remoting中你可以方便的采用事件注册远程回调函数,并方便的利用这种机制将服务器端信息广播到客户端。下面将向读者详细介绍这种分布式多点广播应用程序架构的编写方法。
网络物理结构图
创建以Microsoft .NET Remoting为基础的分布式应用架构第1张
上面便是网络结构示意图,之所以说它是一个典型的分布式应用架构是因为基于这种网络结构十分常见,在证券交易,期货行情,视频会议,远程教学等许多方面都能派上用场。
架构设计
为了形象化抽象的概念,我们先来了解一下电视广播的工作流程,再结合我们的程序理解架构设计的主要思想。
电视广播的流程是由以下四个主要机构参与其中:
1. 节目制作部门。负责制作电视节目。
2. 转播间。负责安排节目制作部门提供的节目的广播方式。
3. 电视塔。负责将电视信号转化为无线电波发送出去。
4. 电视机。负责接受无线电信号并转换成可视的图象。
在我们的程序中也是由四个主要的对象组成,它们的名称和用途分别是:
1. Announcer:信息发送对象。负责发送原始信息,相当于电视节目制作部门。
2. InfoCenter: 信息中心。负责管理信息广播机制。相当于转播间。
3. Server:服务器。管理传送通道,负责发送广播数据流。相当于电视塔。
4. Receiver:接受器。接受广播数据流,转换成我们可以理解的信息格式。相当于电视机。
对象结构如下图所示:
创建以Microsoft .NET Remoting为基础的分布式应用架构第2张
程序设计
首先我们来看一下信息中心InfoCenter对象的编写方法(InfoCenter.cs):
using System;
using System.Runtime.Remoting;
namespace Distribution_Framework
{
	//定义广播事件的参数类
	[Serializable]
	public class BroadcastEventArgs : EventArgs
	{
		private string msg = null;
		public BroadcastEventArgs(string message)
		{
			msg = message;
		}
		public string Message
		{
			get
			{
				return msg;
			}
		}
	}
	public delegate void BroadcastEventHandler(object sender, BroadcastEventArgs submitArgs);
	public class InfoCenter : MarshalByRefObject
	{
		public InfoCenter()
		{
			Console.WriteLine("InfoCenter created.");
		}
		public override object InitializeLifetimeService()
		{
			return null;
		}
		public event BroadcastEventHandler Broadcaster;
		public void Broadcasting(string message)
		{
			BroadcastEventArgs e = new BroadcastEventArgs(message);

			if (Broadcaster != null)
			{
				Broadcaster(this, e);//发出事件
				Console.WriteLine("Broadcast:" + e.Message);
			}
		}
	}
}
要点说明:
public delegate void BroadcastEventHandler(object sender, BroadcastEventArgs submitArgs);
定义了一个事件处理委托及其参数格式。
public event BroadcastEventHandler Broadcaster;
请注意,这一句定义了一个公共事件,需要接受广播信息的远程对象可以通过这个事件向InfoCenter注册使用BroadcastEventHandler委托的远程回调函数。这个机制有点类似有线受费电视,你如果需要收看电视台提供的电视节目请先来登记。
接下来看看Server对象的实现(Server.cs):
using System;
using System.Runtime.Remoting;

namespace Distribution_Framework
{
	class Server
	{
		public static void Main(string[] Args)
		{
			RemotingConfiguration.Configure("Server.exe.config");
			Console.WriteLine("Server is running, Press Enter key to exit.");
			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):
using System;
using System.Runtime.Remoting;
using System.Runtime.Remoting.Channels;
using System.Runtime.Remoting.Channels.Http;

namespace Distribution_Framework
{
	class Receiver : MarshalByRefObject
	{
		InfoCenter infoCenter;
		public Receiver()
		{
		}

		public override object InitializeLifetimeService() 
		{
			return null;
		}

		public void Run()
		{
			RemotingConfiguration.Configure("Receiver.exe.config");
			infoCenter = new InfoCenter();
			//订阅信息
			infoCenter.Broadcaster += new BroadcastEventHandler(this.BroadcastReceiver);
			Console.WriteLine("Ready to Recieve Message...");
			Console.ReadLine();
			//取消订阅
			infoCenter.Broadcaster -= new BroadcastEventHandler(this.BroadcastReceiver);
		}

		public void BroadcastReceiver(object sender, BroadcastEventArgs args)
		{
			Console.WriteLine("Received:" + args.Message);//打印接收信息
		}

		public static void Main()
		{
			Receiver receiver = new Receiver();
			receiver.Run();
		}
	}
}
要点说明:
infoCenter.Broadcaster += new BroadcastEventHandler(this.BroadcastReceiver);
还记得我们在InfoCenter中定义的那个Broadcaster事件吗?这里就是如何向它注册一个远程回调函数,相当于登记收看电视节目了。不想看了的话记得要向它取消登记哦,infoCenter.Broadcaster -= new BroadcastEventHandler(this.BroadcastReceiver);不然多收了你的钱可别耍赖。 :)
public void BroadcastReceiver(object sender, BroadcastEventArgs args)
{
	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):
using System;
using System.Timers;
using System.Runtime.Remoting;
using System.Runtime.Remoting.Channels;
using System.Runtime.Remoting.Channels.Http;


namespace Distribution_Framework
{
	class Announcer
	{
		InfoCenter infoCenter;

		public static void Main(string[] Args)
		{
			Announcer announcer = new Announcer();
			announcer.Run();
			Console.WriteLine("The announcer has been started.");
			Console.ReadLine();
		}

		public void Run()
		{
			RemotingConfiguration.Configure("Announcer.exe.config");
			infoCenter = new InfoCenter();
			Timer timer = new Timer(1000);
			timer.Elapsed += new System.Timers.ElapsedEventHandler(this.timer_Elapsed);
			timer.Enabled = true;
		}

		private void timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
		{
			string msg = "The Time is: " + DateTime.Now.ToString();
			Console.WriteLine("Send Message:" + 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:library infocenter.cs
csc /r:infocenter.dll server.cs
csc /r:infocenter.dll receiver.cs
csc /r:infocenter.dll announcer.cs
请先运行Server.exe然后再运行Announcer.exe,最后你可以多打开几个Receiver,观察它们的工作情况。注意,如果你需要在不同的计算机上向别人演示这个程序的话,请将配置文件中的localhost改成相应的计算机名称或者是IP地址,而无须重新编译。
总结
使用.NET编程总是这么简单和有趣,在上例中,你几乎看不到什么关于"远程"的特殊代码,它非常接近于普通的程序调用,事实上,如果没有进行对 RemotingConfiguration.Configure() 的调用,你根本就不需要进行任何修改即可在单个应用程序域中编译和运行整个应用程序。
本文着重的是定义一个基于.NET Remoting的分布式远程应用架构的设计模式,其一部分设计思想来自于《设计模式》中的Observer模式,如果你对使用事件和委托来实现Observer模式的概念有些模糊的话,请参考拙文:利用C#的Delegate来改进Observer模式
参考文献
MSDN-.NET框架开发者指南:.NET远程处理

免责声明:文章转载自《创建以Microsoft .NET Remoting为基础的分布式应用架构》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇rest-framework之url控制模板汇总——左偏树下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

整理分布式锁:业务场景&amp;amp;分布式锁家族&amp;amp;实现原理

1、引入业务场景 业务场景一出现: 因为小T刚接手项目,正在吭哧吭哧对熟悉着代码、部署架构。在看代码过程中发现,下单这块代码可能会出现问题,这可是分布式部署的,如果多个用户同时购买同一个商品,就可能导致商品出现库存超卖 (数据不一致)现象,对于这种情况代码中并没有做任何控制。 原来一问才知道,以前他们都是售卖的虚拟商品,没啥库存一说,所以当时没有考虑那么多...

单体架构、SOA、微服务

1、单体架构 2、单体架构的拆分 3、SOA与微服务的区别 4、微服务的优缺点 5、微服务的消息 6、服务集成 7、数据的去中心化 一、单体架构 Web应用程序发展的早期,大部分web工程是将所有的功能模块(service side)打包到一起并放在一个web容器中运行,很多企业的Java应用程序打包为war包。其他语言(Ruby,Python或者C++)...

还在用分库分表?看TiDB如何解决海量数据无感扩容难题

近日,一家国产企业级数据库公司 PingCAP 刚刚获得了 2.7 亿美元 D 轮融资,在数据库行业引起了很大反响。在新基建和国产自主化浪潮的推动下,PingCAP 的主打产品 TiDB 数据库热度持续上升。而随着云原生技术的迅速普及,各类大中小企业和技术团队为了更好地节省成本、深入体验云上数据库的灵活性和弹性,也纷纷将目光投向了 TiDB 的云上数据库...

参加了两天QCon会议,你有什么感觉?

  4.23-24两天在北京京仪酒店参加了两天QCon会议,这是我第一次参加QCon会议。可能是对InfoQ期望比较高的原因吧,期望越高失望越大,整体满意度感觉一般吧,不过第一天吃的还是很好的:)以下我把这次参会的一些感觉和收获写一下。 第一天 早上一去,找了几分钟才找到我的名单,签完字发现又没有我的牌子,又跑去二楼现写了一个牌子,这是我有史一来参会第一...

Apache Dubbo

分布式RPC框架Apache Dubbo 1. 软件架构的演进过程 软件架构的发展经历了由单体架构、垂直架构、SOA架构到微服务架构的演进过程,下面我们分别了解一下这几个架构。 1.1 单体架构 架构说明: ​ 全部功能集中在一个项目内(All in one)。 架构优点: ​ 架构简单,前期开发成本低、开发周期短,适合小型项目。 架构缺点: ​ 全部功...

Web内容管理系统 Magnolia 介绍-挖掘优良的架构(1)

Magnolia简介:Magnolia CMS是一家瑞士公司自2003年起发布的一个基于Java的开源内容管理系统。它适合且已被使用在以下领域:电子商务(例如:COOP、Migros、Rossmann)、银行(例如:巴克莱银行、苏格兰银行、ING、American Express)、媒体娱乐(例如:阿拉伯电台、MBC、Foxtel)、政府(例如:美国NAV...