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

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

INetMessageHook定义如下:
   

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

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

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

EsbNetMessageHook
 1 public class EsbNetMessageHook : INetMessageHook
 2     {
 3         #region property
 4         private IList hookList = new ArrayList() ;
 5         public IList HookList
 6         {
 7             set
 8             {
 9                 this.hookList = value ;
10             }
11         }
12 
13         #region Enabled
14         private bool enabled = true ; 
15         public bool Enabled
16         {
17             get
18             {
19                 return this.enabled ;
20             }
21             set
22             {
23                 this.enabled = value ;
24             }
25         }
26         #endregion
27 
28         #endregion
29 
30         #region INetMessageHook 成员
31         public NetMessage CaptureRecievedMsg(NetMessage msg)
32         {    
33             if(! this.enabled)
34             {
35                 return msg ;
36             }
37     
38             if(msg == null)
39             {
40                 return null ;
41             }
42 
43             NetMessage result = msg ;
44             for(int i=0 ;i<this.hookList.Count ;i++)
45             {
46                 INetMessageHook hook = (INetMessageHook)this.hookList[i] ;
47                 result = hook.CaptureRecievedMsg(result) ;
48             }
49 
50             return result ;
51         }
52 
53         public NetMessage CaptureBeforeSendMsg(NetMessage msg)
54         {
55             if(! this.enabled)
56             {
57                 return msg ;
58             }
59 
60             if(msg == null)
61             {
62                 return null ;
63             }
64 
65             NetMessage result = msg ;
66             for(int i=this.hookList.Count-1 ;i>=0 ;i-- )
67             {
68                 INetMessageHook hook = (INetMessageHook)this.hookList[i] ;
69                 result = hook.CaptureBeforeSendMsg(result) ;
70             }
71 
72             return result ;
73         }        
74 
75         #endregion
76     }

    需要特别注意的是,HookList的实现中,逐个调用Hook的CaptureRecievedMsg方法的顺序必须与逐个调用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实现如下:

BaseZipHook
  1 public abstract class BaseZipHook :INetMessageHook
  2     {
  3         public BaseZipHook()
  4         {            
  5         }
  6 
  7         protected abstract byte[] Zip(byte[] data ,int offset ,int size) ;
  8         protected abstract byte[] Unzip(byte[] data ,int offset ,int size) ;
  9         protected abstract bool   IsP2PMessage(NetMessage msg) ;
 10 
 11         #region INetMessageHook 成员
 12 
 13         #region CaptureRecievedMsg
 14         public NetMessage CaptureRecievedMsg(NetMessage msg)
 15         {
 16             if(!this.enabled)
 17             {
 18                 return msg ;
 19             }
 20 
 21             if(! msg.Header.ZipMe)
 22             {
 23                 return msg ;
 24             }
 25 
 26             if(this.IsP2PMessage(msg))
 27             {
 28                 if(! this.zipP2pMessage)
 29                 {
 30                     return msg ;
 31                 }
 32             }
 33 
 34             if(msg.Body == null)
 35             {
 36                 return msg ;
 37             }
 38 
 39             msg.Body = this.Unzip(msg.Body ,0 ,msg.Header.MessageBodyLength) ;
 40             msg.Header.MessageBodyLength = msg.Body.Length ;
 41 
 42             return msg ;
 43         }
 44         #endregion
 45 
 46         #region CaptureBeforeSendMsg
 47         public NetMessage CaptureBeforeSendMsg(NetMessage msg)
 48         {
 49             if(!this.enabled)
 50             {
 51                 return msg ;
 52             }
 53 
 54             if(! msg.Header.ZipMe)
 55             {
 56                 return msg ;
 57             }
 58 
 59             if(this.IsP2PMessage(msg))
 60             {
 61                 if(! this.zipP2pMessage)
 62                 {
 63                     return msg ;
 64                 }
 65             }
 66 
 67             if(msg.Body == null)
 68             {
 69                 return msg ;
 70             }
 71 
 72             msg.Body = this.Zip(msg.Body ,0 ,msg.Header.MessageBodyLength) ;
 73             msg.Header.MessageBodyLength = msg.Body.Length ;
 74 
 75             return msg ;
 76         }
 77         #endregion
 78 
 79         #region Enabled
 80         private bool enabled = true ; 
 81         public bool Enabled
 82         {
 83             get
 84             {
 85                 return this.enabled ;
 86             }
 87             set
 88             {
 89                 this.enabled = value ;
 90             }
 91         }
 92         #endregion
 93 
 94         #region ZipP2pMessage 通常服务端设置为false ,而客户端设置为true
 95         private bool zipP2pMessage = true ; 
 96         public bool ZipP2pMessage
 97         {
 98             get
 99             {
100                 return this.zipP2pMessage ;
101             }
102             set
103             {
104                 this.zipP2pMessage = value ;
105             }
106         }
107         #endregion
108 
109         #endregion
110     }

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

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

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

上一篇:ESFramework介绍之(3)――消息处理器和处理器工厂
转到  :ESFramework 可复用的通信框架(序) 

时间: 2024-07-30 01:55:39

ESFramework介绍之(4)――消息拦截器INetMessageHook的相关文章

ESFramework网络通信框架介绍之(5)――消息分派器IMessageDispatcher

  从2004年7月开始,就一直从事N层C/S架构的服务端的开发,时至今日,慢慢的积累了一些开发经验,ESFramework网络通信框架体系便是这些经验的总结.ESFramework网络通信框架这是一套完全可复用的.灵活的.单纯的.支持N层C/S架构的网络通信框架,内置了对Tcp和Udp协议的支持.ESFramework网络通信框架不仅仅提供了一个基础的C/S框架和大量C/S应用中常用的组件,而且在ESFramework网络通信框架框架之上,引入的一个扩展层--ESFramework网络通信框架

shiro 拦截器链

Shiro使用了与Servlet一样的Filter接口进行扩展:所以如果对Filter不熟悉可以参考<Servlet3.1规范>http://www.iteye.com/blogs/subjects/Servlet-3-1了解Filter的工作原理.首先下图是Shiro拦截器的基础类图: 1.NameableFilter NameableFilter给Filter起个名字,如果没有设置默认就是FilterName:还记得之前的如authc吗?当我们组装拦截器链时会根据这个名字找到相应的拦截器实

AS与FS通信实现 —— ESFramework介绍之(33)

    (本文部分内容只适合ESFramework V0.3+)     在ESFramework介绍之(14)-- AS与FS通信方案 一文中,我们讲到了AS与FS之间基本的通信方案,并且采取了一些策略来保证AS与FS之间的稳定通信.本文我们将给出AS与FS通信的两种实现,即基于Tcp连接池的通信实现和基于Remoting的通信实现.     我们已经知道,AS与FS之间的通信分为两类,一类是非功能通信,一类是功能通信.非功能通信指的是FS向AS注册.注销等通信,这种通信仅仅是FS主动联系AS

Struts2框架学习之六:理解并使用拦截器

前言 拦截器是Struts2框架的核心功能,理解并使用拦截器有助于更灵活使用Struts2.拦截器与Servlet中的过滤器有些类似却又不尽相同.因为在Struts2中拦截器更像一个可插拔的组件,围绕Action和Result进行,可以在方法调用之前.之后使用.通过Struts2的工作流程(后面还会看到一个请求在Struts2中详细的执行流程)可以发现调用一个Action之前之后有许多的拦截器,这些拦截器都通过后才执行具体的action.对于每一个拦截器来说,可以直接返回,从而终止余下的拦截器.

半路杀出程咬金-你的程序是否能做到?Struts 2的拦截器-你手中的程咬金(9)

拦截器(Interceptor)是Struts 2的核心组成部分.很多功能(Feature)都是构建在拦截器基础之上的,例如文件的上传和下载.国际化.转换器和数据校验等,Struts 2利用内建的拦截器,完成了框架内的大部分操作. 在Struts 2文档中对拦截器的解释为--拦截器是动态拦截Action调用的对象.它提供了一种机制,使开发者可以定义一个特定的功能模块,这个模块可以在Action执行之前或者之后运行,也可以在一个Action执行之前阻止Action执行.同时也提供了一种可以提取Ac

ESFramework介绍之(18)―― Tcp用户管理器组件

    当我们的应用中客户端与AS之间是通过Tcp进行通信的时候,通常,应用也要求管理所有在线的用户.这种管理至少包含以下几点:(1) 当用户上线时,记录上线时间(2) 当用户请求服务时,记录请求服务的时间.服务的类型.本次服务下载的数据量(3) 当用户下线时,记录下线时间.并把本次用户登录.请求服务过程中的所有信息持久化保存(如记录到数据库)     在ESFramework中,实现这种管理的是ITcpUserManager组件,通常,该组件由AS使用(因为在AS.FS.IRAS中只有AS是必

ESFramework介绍之(30)―― 消息侦察者 INetMessageSpy

    (本文适用于ESFramework V0.2+)     现在我们回想一下,当网络组件(Tcp/Udp组件)接收到一个消息后,这个消息会流经哪些组件,然后再通过网络组件发送出去了.如果你研究过ESFramework V0.1,你会发现,消息"行走"的路线模型可以用下图表示出来:    请求消息(路径由黑线表示)经过网络组件后,会被Hook链中的各个Hook按照特定的顺序处理,然后到达消息处理器,消息处理器处理请求消息,并给出回复消息(路径由红线表示),回复消息同样再经过Hook

【Struts2框架】第六节拦截器-拦截器介绍和总结

一.拦截器概念 Strrurs拦截器是可插拔式的拦截器:如果我们要使用某个拦截器,只需要在配置文件中应用该拦截器即可. Struts拦截器由struts-default.xml,struts.xml等配置文件中进行管理. Struts2中已经默认启动了大量通用功能的拦截器(这些拦截器以name-class对的形式配置在struts-default.xml文件中),只要我们配置Action的package继承了struts-default包,这些拦截器就会起作用. 拦截器几乎完成了Sturts2框

Mybatis拦截器的实现介绍_java

 MyBatis介绍 MyBatis本是apache的一个开源项目iBatis, 2010年这个项目由apache software foundation 迁移到了google code,并且改名为MyBatis .它支持普通 SQL查询,存储过程和高级映射的优秀持久层框架.MyBatis 消除了几乎所有的JDBC代码和参数的手工设置以及结果集的检索.MyBatis 使用简单的 XML或注解用于配置和原始映射,将接口和 Java 的POJOs(Plain Old Java Objects,普通的