分享
 
 
 

消息与.Net Remoting的分布式处理架构

王朝c#·作者佚名  2008-06-01
窄屏简体版  字體: |||超大  

分布式处理在大型企业应用系统中,最大的优势是将负载分布。通过多台服务器处理多个任务,以优化整个系统的处理能力和运行效率。分布式处理的技术核心是完成服务与服务之间、服务端与客户端之间的通信。

在.Net 1.1中,可以利用Web Service或者.Net Remoting来实现服务进程之间的通信。本文将介绍一种基于消息的分布式处理架构,利用了.Net Remoting技术,并参考了CORBA Naming Service的处理方式,且定义了一套消息体制,来实现分布式处理。

一、消息的定义

要实现进程间的通信,则通信内容的载体——消息,就必须在服务两端具有统一的消息标准定义。从通信的角度来看,消息可以分为两类:Request Messge和Reply Message。为简便起见,这两类消息可以采用同样的结构。

消息的主体包括ID,Name和Body,我们可以定义如下的接口方法,来获得消息主体的相关属性:

public interface IMessage:ICloneable

...{

IMessageItemSequence GetMessageBody();

string GetMessageID();

string GetMessageName();

void SetMessageBody(IMessageItemSequence aMessageBody);

void SetMessageID(string aID);

void SetMessageName(string aName);

}

消息主体类Message实现了IMessage接口。在该类中,消息体Body为IMessageItemSequence类型。这个类型用于Get和Set消息的内容:Value和Item:

public interface IMessageItemSequence:ICloneable

...{

IMessageItem GetItem(string aName);

void SetItem(string aName,IMessageItem aMessageItem);

string GetValue(string aName);

void SetValue(string aName,string aValue);

}

Value为string类型,并利用HashTable来存储Key和Value的键值对。而Item则为IMessageItem类型,同样的在IMessageItemSequence的实现类中,利用HashTable存储了Key和Item的键值对。

IMessageItem支持了消息体的嵌套。它包含了两部分:SubValue和SubItem。实现的方式和IMessageItemSequence相似。定义这样的嵌套结构,使得消息的扩展成为可能。一般的结构如下:

IMessage——Name

——ID

——Body(IMessageItemSequence)

——Value

——Item(IMessageItem)

——SubValue

——SubItem(IMessageItem)

——……

各个消息对象之间的关系如下:

在实现服务进程通信之前,我们必须定义好各个服务或各个业务的消息格式。通过消息体的方法在服务的一端设置消息的值,然后发送,并在服务的另一端获得这些值。例如发送消息端定义如下的消息体:

IMessageFactory factory = new MessageFactory();

IMessageItemSequence body = factory.CreateMessageItemSequence();

body.SetValue("name1","value1");

body.SetValue("name2","value2");

IMessageItem item = factory.CreateMessageItem();

item.SetSubValue("subname1","subvalue1");

item.SetSubValue("subname2","subvalue2");

IMessageItem subItem1 = factory.CreateMessageItem();

subItem1.SetSubValue("subsubname11","subsubvalue11");

subItem1.SetSubValue("subsubname12","subsubvalue12");

IMessageItem subItem2 = factory.CreateMessageItem();

subItem1.SetSubValue("subsubname21","subsubvalue21");

subItem1.SetSubValue("subsubname22","subsubvalue22");

item.SetSubItem("subitem1",subItem1);

item.SetSubItem("subitem2",subItem2);

body.SetItem("item",item);

//Send Request Message

MyServiceClient service = new MyServiceClient("Client");

IMessageItemSequence reply = service.SendRequest("TestService","Test1",body);

在接收消息端就可以通过获得body的消息体内容,进行相关业务的处理。

二、.Net Remoting服务

在.Net中要实现进程间的通信,主要是应用Remoting技术。根据前面对消息的定义可知,实际上服务的实现,可以认为是对消息的处理。因此,我们可以对服务进行抽象,定义接口IService:

public interface IService

...{

IMessage Execute(IMessage aMessage);

}

Execute()方法接受一条Request Message,对其进行处理后,返回一条Reply Message。在整个分布式处理架构中,可以认为所有的服务均实现该接口。但受到Remoting技术的限制,假如要实现服务,则该服务类必须继续自MarshalByRefObject,同时必须在服务端被Marshal。随着服务类的增多,必然要在服务两端都要对这些服务的信息进行治理,这加大了系统实现的难度与治理的开销。假如我们从另外一个角度来分析服务的性质,基于消息处理而言,所有服务均是对Request Message的处理。我们完全可以定义一个Request服务负责此消息的处理。

然而,Request服务处理消息的方式虽然一致,但究竟服务实现的业务,即对消息处理的具体实现,却是不相同的。对我们要实现的服务,可以分为两大类:业务服务与Request服务。实现的过程为:首先,具体的业务服务向Request服务发出Request请求,Request服务侦听到该请求,然后交由其侦听的服务来具体处理。

业务服务均具有发出Request请求的能力,且这些服务均被Request服务所侦听,因此我们可以为业务服务抽象出接口IListenService:

public interface IListenService

...{

IMessage OnRequest(IMessage aMessage);

}

Request服务实现了IService接口,并包含IListenService类型对象的委派,以执行OnRequest()方法:

public class RequestListener:MarshalByRefObject,IService

...{

public RequestListener(IListenService listenService)

...{

m_ListenService = listenService;

}

PRivate IListenService m_ListenService;

IService Members#region IService Members

public IMessage Execute(IMessage aMessage)

...{

return this.m_ListenService.OnRequest(aMessage);

}

#endregion

public override object InitializeLifetimeService()

...{

return null;

}

}

在RequestListener服务中,继续了MarshalByRefObject类,同时实现了IService接口。通过该类的构造函数,接收IListService对象。

由于Request消息均由Request服务即RequestListener处理,因此,业务服务的类均应包含一个RequestListener的委派,唯一的区别是其服务名不相同。业务服务类实现IListenService接口,但不需要继续MarshalByRefObject,因为被Marshal的是该业务服务内部的RequestListener对象,而非业务服务本身:

public abstract class Service:IListenService

...{

public Service(string serviceName)

...{

m_ServiceName = serviceName;

m_RequestListener = new RequestListener(this);

}

IListenService Members#region IListenService Members

public IMessage OnRequest(IMessage aMessage)

...{

//……

}

#endregion

private string m_ServiceName;

private RequestListener m_RequestListener;

}

Service类是一个抽象类,所有的业务服务均继续自该类。最后的服务架构如下:

(图片较大,请拉动滚动条观看)

我们还需要在Service类中定义发送Request消息的行为,通过它,才能使业务服务被RequestListener所侦听。

public IMessageItemSequence SendRequest(string aServiceName,

string aMessageName,IMessageItemSequence aMessageBody)

...{

IMessage message = m_Factory.CreateMessage();

message.SetMessageName(aMessageName);

message.SetMessageID("");

message.SetMessageBody(aMessageBody);

IService service = FindService(aServiceName);

IMessageItemSequence replyBody = m_Factory.CreateMessageItemSequence();

if (service != null)

...{

IMessage replyMessage = service.Execute(message);

replyBody = replyMessage.GetMessageBody();

}

else

...{

replyBody.SetValue("result","Failure");

}

return replyBody;

}

注重SendRequest()方法的定义,其参数包括服务名,消息名和被发送的消息主体。而在实现中最要害的一点是FindService()方法。我们要查找的服务正是与之对应的RequestListener服务。不过,在此之前,我们还需要先将服务Marshal:

public void Initialize()

...{

RemotingServices.Marshal(this.m_RequestListener,

this.m_ServiceName +".RequestListener");

}

我们Marshal的对象,是业务服务中的Request服务对象m_RequestListener,这个对象在Service的构造函数中被实例化:

m_RequestListener = new RequestListener(this);

注重,在实例化的时候是将this作为IListenService对象传递给RequestListener。因此,此时被Marshal的服务对象,保留了业务服务本身即Service的指引。可以看出,在Service和RequestListener之间,采用了“双重委派”的机制。

通过调用Initialize()方法,初始化了一个服务对象,其类型为RequestListener(或IService),其服务名为:Service的服务名 + ".RequestListener"。而该服务正是我们在SendRequest()方法中要查找的Service:

IService service = FindService(aServiceName);

下面我们来看看FindService()方法的实现:

protected IService FindService(string aServiceName)

...{

lock (this.m_Services)

...{

IService service = (IService)m_Services[aServiceName];

if (service != null)

...{

return service;

}

else

...{

IService tmpService = GetService(aServiceName);

AddService(aServiceName,tmpService);

return tmpService;

}

}

}

可以看到,这个服务是被添加到m_Service对象中,该对象为SortedList类型,服务名为Key,IService对象为Value。假如没有找到,则通过私有方法GetService()来获得:

private IService GetService(string aServiceName)

...{

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有