ASP.NET网页编程之.NET可复用TCP通讯层之动静分拨器组件
据说很厉害,甚至可以把C#也干掉^_^,不过也很复杂,本来C++已经够复杂的。有人甚至还提出把这个东东引进标准,我觉得基本上不可能的。 上一篇次要讲到了Tcp通讯层中的中心组件DDTcp组件的完成,Tcp组件是全部通讯层的动静驱动源,乃至,能够将Tcp组件看做是我们全部服务器体系的动静驱动源,动静处置历程从这里激发。相似的动静驱动源另有公布的WebService接口、Remoting接口等。明天我们必要存眷的是Tcp通讯层中的“中心”组件DD动静分拨器组件ITcpReqStreamDispatcher,人人已夙昔文的组件干系图中看到了动静分拨器的大抵地位和感化了,它是Tcp通讯组件和动静处置器之间的“桥梁”。我们再对前文形貌的通讯层组件之间干系的一段话回忆一下:“当收集(Tcp)组件从某个Tcp毗连上吸收到一个哀求时,会将哀求转发给动静分拨器,动静分拨器经由过程IDataStreamHelper组件猎取哀求动静的范例,然后依据此范例请求处置器工场创立对应范例的哀求处置器,哀求处置器处置哀求并前往了局。接上去再由收集组件把了局前往给终端用户。在动静分拨器举行哀求动静分拨之前,大概触及一系列的操纵,像动静加密/解密、动静决裂/重组、动静考证等。”
下面的形貌中已表现出了动静分拨器的次要职责,在了解了动静分拨器职责的基本上,我们能够进一步来看看动静分拨器的界说和完成了。
二.动静分拨器组件
1.动静分拨器组件接口的界说
动静分拨器的接口很复杂:
publicinterfaceITcpReqStreamDispatcher:IReqestStreamDispatcher
{
ArrayListDealRequestMessage(RequestDatarequestData,outbyte[]leftData,refRequestValidationvalidation);//同步复兴
boolDealRequestMessage(RequestDatarequestData,NetworkStreamuserStream,outbyte[]leftData);//异步复兴
}
这个接口只要两个办法,第二个办法用于异步发送复兴(即绕开Tcp组件发送复兴),该办法的中心部分能够由第一个办法完成,我们把注重力放在第一个办法上,而Tcp组件与动静分拨器举行交互的也恰是第一个办法。我先注释一下这个办法的几个参数的寄义:
RequestData是对哀求动静的封装:
//从收集吸收到的原始数据的封装
publicclassRequestData
{
publicintConnectID=0;
publicboolIsFirstMsg=false;//标记是不是为毗连创建后的第一条动静
publicbyte[]Buff=null;//吸收数据缓冲区,大概其头部包括前次未处置完的数据
publicintValidCount=0;//缓冲区中无效字节的个数>=本次吸收的字节数
}
后面已提到过,ConnectID用于标记每个Tcp毗连,IsFirstMsg用于标明是不是为tcp毗连创建后的第一个动静,由于我们大概必要对第一个动静举行分外的考证,好比,果第一个动静不是登录哀求,就封闭该Tcp毗连。
第二个参数leftData,暗示RequestData.Buff中的数据经由动静决裂器决裂以后余下的数据(一条非完全的动静),这些数据被Tcp组件用来放鄙人一次收到的数据的头部举行动静重组。
第三个参数validation,是个ref参数,用于关照Tcp组件抵消息考证的了局,假如考证失利,Tcp组件将封闭对应的Tcp毗连。
该办法的前往值是复兴的汇合,每个复兴对应一个哀求,而RequestData.Buff中的数据大概决裂成多个哀求。别的要注重,有些哀求多是没有复兴动静的。
在我们的Tcp组件的两种完成中,都能够看到相似上面的与动静分拨器交互的语句:
//处置哀求
byte[]leftData=null;
ArrayListrepondList=this.messageDispatcher.DealRequestMessage(key.RequestData,outleftData,refkey.Validation);
if(this.validateRequest)
{
if(key.Validation.gotoCloseConnection)
{
this.DisposeOneConnection(streamHashCode,key.Validation.cause);
}
}
2.动静分拨器组件基础元素的完成
正如在完成Tcp组件之前必要构建一些基础元素,在完成动静分拨器之前也是云云,用于撑持动静分拨器完成的基础元素包含:IDataStreamHelper、动静决裂器、动静处置器工场、ITcpStreamDispatcherHook等。
(1)IDataStreamHelper动静决裂器
IDataStreamHelper,前文中已提到,IDataStreamHelper用于从哀求/复兴动静中提作废息的“元数据”,并供应一些帮助办法,每一个特定的使用,它们对IDataStreamHelper的完成多是纷歧样的。IDataStreamHelper接口界说以下:
///<summary>
///IDataStreamHelper通讯协定的面向流帮助举措措施。
///</summary>
publicinterfaceIDataStreamHelper:IStringEncoder
{
intMaxRecieveBuffSize{get;}//吸收缓冲区的巨细
intMessageHeaderLength{get;}//动静头的长度
intOffsetOfLengthField{get;}//暗示动静长度的字段在动静头中的偏移
IDataStreamHeaderParseMessageHeader(byte[]data,intoffset);//剖析动静头
LengthTypeInHeaderLengthTypeInHeader{get;}
byte[]GetRespondWhenFailure(byte[]reqData,ServiceFailureTypefailType);//依据服务失利范例猎取失利复兴动静
byte[]GetRespondWhenFailure(byte[]reqData,stringerrorMsg);
}
///<summary>
///StringEncoder限制字符串编码格局
///</summary>
publicinterfaceIStringEncoder
{
stringGetStrFromStream(byte[]stream,intoffset,intlen);
byte[]GetBytesFromStr(stringss);
}
///<summary>
///ServiceFailureType服务失利范例
///</summary>
publicenumServiceFailureType
{
InvalidMessge,ParseFailure,HandleFailure,ServiceStopped,ServiceIsNotExit,ServerIsBusy
}
IDataStreamHeader便是我们所说的动静的“元数据”,如其名所示,它也是动静的“动静头”。请让我增补申明一下,按照我的履历,动静由动静头Header和动静主体Body构成,动静头用于寄存动静的“元数据”等信息,而动静主体用于寄存与特定哀求相干的数据。动静头的长度流动,好比都是64字节或都是128字节。哀求动静和复兴动静公用不异格局的动静头。我们来看看动静头接口IDataStreamHeader的界说:
publicinterfaceIDataStreamHeader
{
intMessageLength{get;set;}//本动静长度
intTypeKey{get;set;}//哀求的目次范例
intServiceKey{get;set;}//哀求范例
intServiceItemIndex{get;set;}//哀求细分索引
intRandomNum{get;set;}//用于将复兴与哀求逐一对应起来
intResult{get;set;}//服务了局
stringUserID{get;set;}//收回哀求的用户编号
byte[]ToDataStream();//将动静头转化为流,流的长度位动静头的长度
voidToDataStream(byte[]buff,intoffset);
}
必要注释一下TypeKey、ServiceKey、ServiceItemIndex,我们实践大将服务范例分为三级,能够举个不太得当的例子让人人有个理性的熟悉。好比,生存中的衣、食、住、行能够作为分歧的TypeKey,而“衣”中的春装、冬装可作为ServiceKey,而“春装”中的T恤、茄克可作为ServiceItemIndex。关于服务的范例,你能够依据本人的志愿分红恣意层级,但据我的履历,一般情形下,三层已够用了。
(2)动静决裂器
后面已屡次提到动静决裂器MessageSplitter,它用于将吸收缓冲区中的数据决裂成一个个完全的动静,而且把余下的非完全数据前往,其接口界说以下:
publicinterfaceIMessageSplitter
{
voidInitialize(intmaxBuffSize,intheaderLen,intoffSetLenField,LengthTypeInHeaderlenType);
ArrayListSplitRequestMsgs(byte[]buff,intvalidCount,outbyte[]leftData);//ArrayList中每笔记录都是是byte[],暗示一个完全的哀求
}
//动静头中的长度是body长度仍是总长度
publicenumLengthTypeInHeader
{
TotalLen,BodyLen
}
个中,Initialize办法中的参数都能够由IDataStreamHeader供应。leftData是余下的非完全动静的数据。SplitRequestMsgs办法前往的汇合中是一条条完全的哀求动静。
(3)动静处置器工场
动静处置器工场依据动静的范例(TypeKey、ServiceKey)创立对应的动静处置器来出来该动静,其接口界说以下:
publicinterfaceIRequestDealerFactory
{
IRequestDealerCreateDealer(intrequestType,intserverTypeKey);//serverTypeKey好比乡村代号
eventCbackRequestRecievedRequestRecieved;
}
CreateDealer办法前往的IRequestDealer就是动静处置器,每个动静处置器用于处置某种特定范例(ServiceKey)的一切哀求。一般,能够将动静处置器封装成插件DLL,以完成功效服务的“热插拔”。
(4)动静处置器
动静处置器IRequestDealer界说以下:
publicinterfaceIRequestDealer
{
byte[]DealRequestMessage(RoundedRequestMsgreqMsg);//同步复兴
eventCbackRequestRecievedRequestRecieved;
}
publicdelegatevoidCbackRequestRecieved(RoundedRequestMsgroundedMsg);
///<summary>
///RoundedRequestMsg对应于一条完全的哀求
///</summary>
publicstructRoundedRequestMsg
{
publicintConnectID;//哀求所对应的Tcp毗连
publicbyte[]Data;
}
RoundedRequestMsg.Data是经动静决裂器决裂失掉的一个完全的哀求动静,一个字节未几、一个字节也很多。
(5)ITcpStreamDispatcherHook
ITcpStreamDispatcherHook是一个Hook,它为用户供应了一个自界说的对哀求/复兴动静举行操纵的拔出点。ITcpStreamDispatcherHook由TcpStreamDispatcher利用,用于对哀求动静和复兴动静举行截获,然后处置或转换这些动静,好比经常使用的处置/转换操纵包含:加密/解密、动静考证等等。ITcpStreamDispatcherHook界说以下:
///<summary>
///ITcpStreamDispatcherHook由TcpStreamDispatcher利用,用于对哀求动静和复兴动静举行截获,然后处置转换这些动静,
///好比加密/解密。
///</summary>
publicinterfaceITcpStreamDispatcherHook
{
//转换动静
byte[]CaptureRequestMsg(byte[]roundedMsg);
byte[]CaptureRespondMsg(byte[]roundedMsg);
//考证动静,以下考证的动静是还没有被捕捉的动静
boolVerifyFirstMsgOfUser(byte[]roundedMsg,refRequestValidationvalidation);
boolVerifyOtherMessage(byte[]roundedMsg,refRequestValidationvalidation);
}
关于这个接口中各办法的寄义能够在动静分拨器的完成中更好的了解!
3.动静分拨器完成
在前述的基础元素的基本上,完成动静分拨器十分复杂,我们来看其中心办法DealRequestMessage的完成源码:
privateIMessageSplittercurMsgSplitter=newMessageSpliter();
privateIDataStreamHelpercurMsgHelper;//必需设置
privateIRequestDealerFactorycurDealerFactory;//必需设置
privateITcpStreamDispatcherHooktcpStreamDispatcherHook;
publicArrayListDealRequestMessage(RequestDatarequestData,outbyte[]leftData,refRequestValidationvalidation)
{
//动静决裂
ArrayListrespondList=newArrayList();
ArrayListreqList=this.curMsgSplitter.SplitRequestMsgs(requestData.Buff,requestData.ValidCount,outleftData);
if(reqList==null)
{
returnrespondList;
}
boolverified=true;
for(inti=0;i<reqList.Count;i++)
{
byte[]theData=(byte[])reqList;
#region考证动静
if(requestData.IsFirstMsg&&(i==0))
{
verified=this.tcpStreamDispatcherHook.VerifyFirstMsgOfUser(theData,refvalidation);
}
else
{
verified=this.tcpStreamDispatcherHook.VerifyOtherMessage(theData,refvalidation);
}
if(!verified)
{
if(validation.gotoCloseConnection)
{
returnnull;
}
this.AddRespondToList(respondList,this.curMsgHelper.GetRespondWhenFailure(theData,ServiceFailureType.InvalidMessge));
continue;
}
#endregion
//接插,捕捉/转换哀求动静
byte[]reqData=this.tcpStreamDispatcherHook.CaptureRequestMsg(theData);
#region处置动静
//处置动静
IDataStreamHeaderheader=this.curMsgHelper.ParseMessageHeader(reqData,0);
IRequestDealerdealer=this.curDealerFactory.CreateDealer(header.ServiceKey,header.TypeKey);
if(dealer==null)
{
this.AddRespondToList(respondList,this.curMsgHelper.GetRespondWhenFailure(reqData,ServiceFailureType.ServiceIsNotExit));
continue;
}
RoundedRequestMsgroundReqMsg=newRoundedRequestMsg();
roundReqMsg.ConnectID=requestData.ConnectID;
roundReqMsg.Data=reqData;
try
{
byte[]respondData=dealer.DealRequestMessage(roundReqMsg);
if(respondData!=null)
{
this.AddRespondToList(respondList,respondData);
}
}
catch(Exceptionee)
{
this.AddRespondToList(respondList,this.curMsgHelper.GetRespondWhenFailure(reqData,ee.Message));
}
#endregion
}
returnrespondList;
}
//将复兴动静加密后放进list
privatevoidAddRespondToList(ArrayListlist,byte[]theRespondData)
{
//接插,捕捉/转换复兴动静
byte[]respondData=this.tcpStreamDispatcherHook.CaptureRespondMsg(theRespondData);
list.Add(respondData);
}
假如你是一向按按次读上去的,了解下面的完成必定不成甚么成绩。到这里,Tcp通讯层的一切主要的举措措施基础都已先容终了,最初,给出了提醒,即,在你的使用中,怎样利用这个可复用的Tcp通讯层。步骤以下:
(1)完成IDataStreamHelper接口。
(2)完成IReqestStreamDispatcher接口,假如接纳的是Tcp协定,则可间接利用参考完成TcpStreamDispatcher
(3)完成各类哀求处置器,这些处置器完成IRequestDealer接口。
(4)完成IRequestDealerFactory接口。
接上去,另有甚么?实在,另有良多,都能够进步到框架的条理,以便复用。好比,后面我们处置动静都是基于流(byte[])的情势,在此基本上,我们能够更上一层,接纳基于工具的情势DD即,将哀求动静和复兴动静都封装成类,这就触及了流的剖析(流=>工具)和工具序列化(动静工具=>流)成绩;别的,我们乃至能够将Tcp用户办理归入到框架的高度,以举行复用,好比,一般基于Tcp服务的体系都必要办理在线的Tcp用户,并纪录Tcp用户哀求服务的详细信息、在线工夫等,这些经由优秀的剖析归纳综合都能够进步到复用的高度。今后偶然间,我会将如许的履历和人人分享。
最初,把EnterpriseServerBase类库中的Network定名空间中的源码和人人共享,但愿对人人有所匡助!(另,该定名空间中已包括了上述的基于工具的动静和Tcp用户办理的可复用组件)。
其实Java之所以在曾经独步天下,就是因为他的跨平台、安全性,这两方面,效率可不是Java的强项,反而是他最短的一块挡板,虽然net总是用理论证明比.NET快。 逐步缩小出错代码段的范围,最终确定错误代码的位置。 这也就是最近几年来随着各种新的后台技术的诞生,CGI应用在Internet上越来越少的原因。CGI方式不适合大访问量的应用。 当然我们在选择Asp.net主机是,除了要考虑服务提供商在版本是否是实时更新以外,机房的环境和配置也是非常重要的,通常选择骨干网的机房,在速度和稳定性上会非常有保证。 在asp.net虚拟主机的服务提供商中,目前首推的是CNNIC的其中一家域名注册机构---时代互联(www.now.net.cn),他们早在2001年微软刚推出Asp.net时就推出了对应的Asp.net虚拟主机了,经笔者的使用测试,他提供的Asp.net性能非常的稳定,版本也会定期的更新,目前他的 能产生和执行动态、交互式、高效率的站占服务器的应用程序。运用ASP可将VBscript、javascript等脚本语言嵌入到HTML中,便可快速完成网站的应用程序,无需编译,可在服务器端直接执行。容易编写。 ASP是把代码交给VBScript解释器或Jscript解释器来解释,当然速度没有编译过的程序快了。 是指转换后的Servlet程序代码的行数。这给调试代码带来一定困难。所以,在排除错误时,可以采取分段排除的方法(在可能出错的代码前后输出一些字符串,用字符串是否被输出来确定代码段从哪里开始出错)。
页:
[1]