ESFramework介绍之(4)――消息拦截器INetMessageHook

ESFramework通过INetMessageHook支持消息加密、压缩等功能。可仅处理消息主体或整体消息。支持多个Hook串联处理,需注意处理顺序。文章还介绍了EsbNetMessageHook和BaseZipHook的具体实现。
网络上传输的消息经常是经过加密和压缩,有的特定类型的消息可能还需要进行其它变形,ESFramework通过INetMessageHook对这些功能提供支持。需要说明的是,ESFramework对消息进行截获(Hook)处理有两种方式,一是仅仅Hook处理消息主体(Body),而不对消息头作任何变换;另一种方式是对整个消息(包括消息头和主体)都进行Hook处理。通常,第一种方式已经能够满足我们的大多数应用,并且效率也更高,如果应用有更特殊的要求,可以采用第二种方式。本文先介绍第一种方式,后面的文章中会对第二种给予讲解。

INetMessageHook定义如下:

1 public interface INetMessageHook
2 {
3 // 转换消息
4 NetMessageCaptureRecievedMsg(NetMessagemsg); // 在交给处理器之前
5 NetMessageCaptureBeforeSendMsg(NetMessagemsg); // 在发送出去之前
6
7 bool Enabled{ get ; set ;} // 是否启用本Hook
8 }

通过 INetMessageHook 接口可以看到,当消息进入系统时回被 CaptureRecievedMsg 方法截获(比如,进行解密处理),当把消息发送到网络之前,将被 CaptureBeforeSendMsg 方法截获(比如,进行加密处理)。

如果有多个INetMessageHook,则可以形成一个HookList,消息经过HookList时,分别按顺序被每个INetMessageHook处理,ESFramework中的HookList的参考实现是EsbNetMessageHook,并且它也实现了INetMessageHook接口,这样就可以把一个Hook链当作一个Hook了。

其源码如下:

ContractedBlock.gif ExpandedBlockStart.gif EsbNetMessageHook
<!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>-->1publicclassEsbNetMessageHook:INetMessageHook
2{
3#regionproperty
4privateIListhookList=newArrayList();
5publicIListHookList
6{
7set
8{
9this.hookList=value;
10}
11}
12
13#regionEnabled
14privateboolenabled=true;
15publicboolEnabled
16{
17get
18{
19returnthis.enabled;
20}
21set
22{
23this.enabled=value;
24}
25}
26#endregion
27
28#endregion
29
30#regionINetMessageHook成员
31publicNetMessageCaptureRecievedMsg(NetMessagemsg)
32{
33if(!this.enabled)
34{
35returnmsg;
36}
37
38if(msg==null)
39{
40returnnull;
41}
42
43NetMessageresult=msg;
44for(inti=0;i<this.hookList.Count;i++)
45{
46INetMessageHookhook=(INetMessageHook)this.hookList[i];
47result=hook.CaptureRecievedMsg(result);
48}
49
50returnresult;
51}
52
53publicNetMessageCaptureBeforeSendMsg(NetMessagemsg)
54{
55if(!this.enabled)
56{
57returnmsg;
58}
59
60if(msg==null)
61{
62returnnull;
63}
64
65NetMessageresult=msg;
66for(inti=this.hookList.Count-1;i>=0;i--)
67{
68INetMessageHookhook=(INetMessageHook)this.hookList[i];
69result=hook.CaptureBeforeSendMsg(result);
70}
71
72returnresult;
73}
74
75#endregion
76}

需要特别注意的是,HookList的实现中,逐个调用HookCaptureRecievedMsg方法的顺序必须与逐个调用CaptureBeforeSendMsg方法的顺序相反,这就是为什么EsbNetMessageHook实现CaptureBeforeSendMsg方法时,出现下列代码的原因:

for ( int i = this .hookList.Count - 1 ;i >= 0 ;i -- )

为了说明为什么需要颠倒Hook链的情况,可以举个例子,假设有一个“原始消息”从系统1发送到系统2,其间经过了两个Hook,一个加密Hook,一个是压缩Hook,则可表示如下:
系统1=》原始消息=》加密=》压缩=》发送
系统2=》接收消息=》解压缩=》解密=》原始消息

还要提醒的是,在具体的Hook实现中,截获处理经常改变Body的大小,如果Body的大小真的发生了变化,一定要更新消息头(IMessageHeader)中的MessageBodyLength字段。

通常,采用Hook时,服务端与客户端是对称的,所以你可以把所有的Hook实现放在一个Dll中,这样服务端和客户端可以共同使用这个Hook Dll了。

由于对网络消息进行压缩是常见的需求,所以我把BaseZipHook纳入到了ESFramework中,并且,这也是IMessageHeader存在ZipMe属性的原因。ZipMe属性用于通知BaseZipHook是否对接收到的本条消息进行解压缩,是否在发送本消息之前进行压缩。

BaseZipHook
实现如下:

ContractedBlock.gif ExpandedBlockStart.gif BaseZipHook
<!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>-->1publicabstractclassBaseZipHook:INetMessageHook
2{
3publicBaseZipHook()
4{
5}
6
7protectedabstractbyte[]Zip(byte[]data,intoffset,intsize);
8protectedabstractbyte[]Unzip(byte[]data,intoffset,intsize);
9protectedabstractboolIsP2PMessage(NetMessagemsg);
10
11#regionINetMessageHook成员
12
13#regionCaptureRecievedMsg
14publicNetMessageCaptureRecievedMsg(NetMessagemsg)
15{
16if(!this.enabled)
17{
18returnmsg;
19}
20
21if(!msg.Header.ZipMe)
22{
23returnmsg;
24}
25
26if(this.IsP2PMessage(msg))
27{
28if(!this.zipP2pMessage)
29{
30returnmsg;
31}
32}
33
34if(msg.Body==null)
35{
36returnmsg;
37}
38
39msg.Body=this.Unzip(msg.Body,0,msg.Header.MessageBodyLength);
40msg.Header.MessageBodyLength=msg.Body.Length;
41
42returnmsg;
43}
44#endregion
45
46#regionCaptureBeforeSendMsg
47publicNetMessageCaptureBeforeSendMsg(NetMessagemsg)
48{
49if(!this.enabled)
50{
51returnmsg;
52}
53
54if(!msg.Header.ZipMe)
55{
56returnmsg;
57}
58
59if(this.IsP2PMessage(msg))
60{
61if(!this.zipP2pMessage)
62{
63returnmsg;
64}
65}
66
67if(msg.Body==null)
68{
69returnmsg;
70}
71
72msg.Body=this.Zip(msg.Body,0,msg.Header.MessageBodyLength);
73msg.Header.MessageBodyLength=msg.Body.Length;
74
75returnmsg;
76}
77#endregion
78
79#regionEnabled
80privateboolenabled=true;
81publicboolEnabled
82{
83get
84{
85returnthis.enabled;
86}
87set
88{
89this.enabled=value;
90}
91}
92#endregion
93
94#regionZipP2pMessage通常服务端设置为false,而客户端设置为true
95privateboolzipP2pMessage=true;
96publicboolZipP2pMessage
97{
98get
99{
100returnthis.zipP2pMessage;
101}
102set
103{
104this.zipP2pMessage=value;
105}
106}
107#endregion
108
109#endregion
110}

BaseZipHook是一个抽象类,具体实现的压缩算法由派生类通过覆写ZipUnzip方法提供。如果要实现一个具体的ZipHook,你可以从BaseZipHook继承,并采用ZipHelper提供的压缩/解压缩功能。

到现在为止,我们已经讨论了关于消息的比较多的内容了,但还有一个非常重要的组件没有讲到,那就是消息分派器ITcpStreamDispatcher,消息分派器直接与Tcp组件或Udp组件联系,并且所有消息的进出都要经过ITcpStreamDispatcher,所以分派器是一个对消息进行Hook的理想位置,并且消息分派器会把具体的消息分派到对应的消息处理器上。欲知道ITcpStreamDispatcher的原理与实现,请继续关注下文:

ESFramework介绍之(5)――消息分派器ITcpStreamDispatcher


上一篇:ESFramework介绍之(3)――消息处理器和处理器工厂

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



评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值