ESFramework介绍之(2)――网络通信消息NetMes

系统 2029 0
较之 C++ 而言, .NET 是一个更加“动态”的平台,其动态能力建立在反射机制之上,而反射的基础是“元数据”。

上文已经提到过,如果一个框架要为我们的应用做更多的事情,那么这个框架必须建立更多的标准,必须对框架自己要处理的消息有更多的了解,所以,每个消息都要是自描述的,也就是说每个消息要包含它自己的“元数据”。那么,“元数据”位于消息的何处了?你一定想到了,对,是消息头( MessagHeader )。

ESFramework 中,消息 NetMessage 由“消息头 + 主体”构成,并且消息头和主体都必须实现上文讲到的 IContract 接口。消息头既是本条 NetMessage 的元数据,其中包含了诸如消息长度、消息类型等描述信息。 ESFramework 为了能识别每个消息的元数据,必须再建立一个“标准”,这个标准便是 IMessageHeader 接口。为了简化后面的计算和应用, ESFramework 要求所有的消息头的长度是固定的,比如都是 64 字节。注意,固定消息头的长度不是必须的,但是这会降低框架的复杂度。
我们来看看 IMessageHeader 中包含了些什么信息:
ESFramework介绍之(2)――网络通信消息NetMessage

1 public interface IMessageHeader: IContract , ICloneable
2 {
3 int MessageBodyLength{ get ; set ;} // 本消息主体的长度
4 int TypeKey{ get ; set ;} // 请求的服务目录类型
5 int ServiceKey{ get ; set ;} // 请求类型
6 int ServiceItemIndex{ get ; set ;} // 请求细分索引
7 int RandomNum{ get ; set ;} // 用于将回复与请求一一对应起来
8 int Result{ get ; set ;} // 服务结果,1表示成功。其它值对应ServiceResultType
9 string DestUserID{ get ; set ;} // 接收消息的目标用户编号
10 string UserID{ get ; set ;} // 发出请求的用户编号
11 bool P2PAck{ get ; set ;} // 仅仅对P2P消息有效,1表示为服务器转发P2P消息的Ack,Result反映了转发成功还是失败。Ack消息主体为null
12 bool ZipMe{ get ; set ;} // 控制对于本条消息是否启用压缩/解压缩,如果有些消息比较短小,则将IMessageHeader.ZipMe设为false
13 }

IMessageHeader 现在已经包含了比较多的内容了,其实刚开始时, IMessageHeader 仅仅需要 32 个字节就足够,随着 ESFramework 的演化成长,越来越多的信息慢慢加了进来,现在 IMessageHeader 的长度基本上需要 96 字节。加进来的内容对很多应用是必须的。

比如, DestUserID 表明了本条消息不是交给服务器处理的,而是要服务器转发给 ID DestUserID 的用户,这为框架引入了处理“ P2P 消息”的能力;有时,用户可能需要发送一系列按顺序的 P2P 消息,如果是基于 UDP ,则必须要等到对方确认收到上一个消息后,才可以发送下一个消息,于是就有了 P2PAck 字段。基于对网络上传输的消息进行压缩是常见的要求,而有些比较短小的消息又不必进行压缩的情况,就出现了 ZipMe 字段,表明消息是否被压缩 / 解压过。

而在你的具体应用中,消息头应该包括哪些内容,由你的应用的需求来决定,比如,你的应用可能从来不需要处理 P2P 消息,那么在实现 IMessageHeader 接口时,就不需要关注 DestUserID 字段和 P2PAck 字段,并且在你的实际的消息头的字节流中也不需要为它们提供“位置”;而且在使用 ESFramework 装配你的应用的时候,也不用“接插”“ P2PMessage 处理器”。这是非常灵活的。

刚才看到的是消息头的结构,那么消息主体是什么了?在框架这一层,由于框架对所有的具体消息的主体内容一无所知,即使框架知道消息主体可以被解析为一个 IContract “对象”,但是在这一层,并没有足够的信息给框架去将主体解析为 IContract 。所以,框架中的消息主体仍然用字节流 byte[] 表示,而且框架也根本不关心这个消息主体如何解析、如何处理,这些都是应用的事情。框架已经通过消息的元数据对该消息有足够的了解了。
消息 NetMessage 的定义如下:

1 [Serializable]
2 public class NetMessage
3 {
4 public IMessageHeaderHeader = null ;
5 public byte []Body = null ; // 可以经过压缩、变换Hook
6 public object Tag = null ; // 用于在将NetMessage交给IDataDealer时传递额外的信息,不影响ToStream,且很少使用
7
8 public NetMessage()
9 {
10 }
11
12 #region Ctor,ToStream
13 public NetMessage(IMessageHeaderheader, byte []body)
14 {
15 //省略实现......
23 }
24
25 public byte []ToStream()
26 {
27 //省略实现......
41 }
42 #endregion
43
44 #region Length
45 public int Length
46 {
47 //省略实现......
57 }
58 #endregion
59
60 }

Tag 字段用于存放可能在后面的消息处理链中需要使用到的额外信息,比如,基于 UDP 时, Tag 可以存放发送本条消息的客户的 IPEndPoint ,而这个信息可能会被后面的消息处理器用到。
ESFramework介绍之(2)――网络通信消息NetMessage
RoundedMessage包含了比NetMessage更丰富的信息,从网络进口接收到的实际上是RoundedMessage,有时消息分配器或处理器可能需要用到类似ConnectID这样的信息。

在客户端和应用这一层, NetMessage 可以向下转换,因为此时,我们已经知道了消息主体的结构,这个消息主体已经可以被解析为 IContract 了,所以 NetMessage 可以转换为 Message
ESFramework介绍之(2)――网络通信消息NetMessage

Message
<!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--> public class Message
{
private IMessageHeaderheader;
private IContractbody;

public Message(IMessageHeadertheHeader,IContracttheBody)
{
//省略实现......
}

public NetMessageToNetMessage()
{
//省略实现......
}

#region ToStream,GetStreamLength
public int GetStreamLength()
{
//省略实现......
}

public byte []ToStream()
{
//省略实现......
}

public void ToStream( byte []buff, int offset)
{
//省略实现......
}
#endregion

#region Header,Body,MessageHelper
public IMessageHeaderHeader
{
//省略实现......
}

public IContractBody
{
//省略实现......
}
#endregion

}

可以看到,

NetMessage 已经是一个完全的面向对象的消息了。而至于主体到底含有什么具体的内容,还需要对主体 IContract 向下转换到具体的协议上才行。这通常是消息处理器的工作。

关于消息处理器和处理器工厂的介绍,请留意下篇文章。

ESFramework 介绍之( 3 ―― 消息处理器和处理器工厂


上一篇: ESFramework介绍之(1)――网络通信消息协议接口IContract

转到: ESFramework 可复用的通信框架(序)

ESFramework介绍之(2)――网络通信消息NetMessage


更多文章、技术交流、商务合作、联系博主

微信扫码或搜索:z360901061

微信扫一扫加我为好友

QQ号联系: 360901061

您的支持是博主写作最大的动力,如果您喜欢我的文章,感觉我的文章对您有帮助,请用微信扫描下面二维码支持博主2元、5元、10元、20元等您想捐的金额吧,狠狠点击下面给点支持吧,站长非常感激您!手机微信长按不能支付解决办法:请将微信支付二维码保存到相册,切换到微信,然后点击微信右上角扫一扫功能,选择支付二维码完成支付。

【本文对您有帮助就好】

您的支持是博主写作最大的动力,如果您喜欢我的文章,感觉我的文章对您有帮助,请用微信扫描上面二维码支持博主2元、5元、10元、自定义金额等您想捐的金额吧,站长会非常 感谢您的哦!!!

发表我的评论
最新评论 总共0条评论