搞拓展性、灵活性的数据包过滤机制

来源:互联网 发布:linux cat 查看日志 编辑:程序博客网 时间:2024/05/20 10:53

/*搞拓展性、灵活性的数据包过滤机制
功能说明: 背景:
项目要求过滤掉上报比较频繁的高通数据包,由于APK的性能限制,最终决定在基线完成这个功能,但是由于手机代码不完整,所以只能在上报数据包的出口函数即log_commit中添加过滤机制,这里能够看到的仅仅是二进制码流,所以要将数据包解析出来,然后进行过滤判断。同时每个数据包,可以按照不同的时间跨度进行过滤。例如:有的数据包是1秒最多上报一次,如果多余一次则过滤掉多出来的。有的数据包则是500毫秒上报一次。
代码特点: 面临的两个难题:
1、可拓展性:最简单的方式添加或者删除一个要过滤的数据包,要能够匹配多种样式的判断条件
2、性能:由于是在log_commit中添加处理,就是说每一个数据包都会进行判断,因此性能很重要。

先看看最后的成品代码:
在 log_commit中插入IsFilterLogs来判断是否需要过滤,是则直接返回,不发送数据包。

c代码
void log_commit (PACK(void *) ptr)
{

if (ptr)
{
if(TRUE == IsFilterLogs((char*)ptr))
{
return;
}
//其他代码
}


过滤数据的具体处理
c代码
int IsFilterLogs(char* Msg)
{

BEGIN_FILTER
FILTER_LOG(FILTER_LOG0, 500)
FILTER_LOG(FILTER_LOG2, 200)
END_FILTER
}

如果需要添加一个过滤只需要添加一行 FILTER_LOG(FILTER_LOG2, 200)就可以了。FILTER_LOG2是logcode,200是时间跨度,单位MS。

我把所有的流程处理全部封装成宏隐藏起来。实现真正的OCP。

我们先看看宏展开后的代码:
c代码
int IsFilterLogs(char* Msg)
{
unsigned short LogCode = 0;
unsigned int TimeStamp = 0;

LogCode = *(unsigned short*)(Msg + 2);
TimeStamp = *(unsigned int*)(Msg + 4);

int ret = 0;

do
{
if(FILTER_LOG0 == LogCode)
{
static unsigned int LastTimeStamp = 0;

ret = IsFilterLog(TimeStamp, &LastTimeStamp, 500);
break;
}

if(FILTER_LOG2 == LogCode)
{
static unsigned int LastTimeStamp = 0;

ret = IsFilterLog(TimeStamp, &LastTimeStamp, 600);
break;
}

}while(0);

return ret;
}

其中IsFilterLog是具体的业务处理,不作讨论。
这里用到两个技巧:
1、do{}while(0)
所有需要过滤的数据包都是用if条件来判断的,有人会说你为什么不用表驱动,因为效率,表驱动需要循环,其效率没有直接的if判断来的快。
这个技巧可以让我在找到对应的logcode,并且处理完成以后,直接跳出while循环不再判断其他的logcode。
为什么不用if else?因为不好抽象,第一个if前面是没有else的。
为什么不用switch case?因为switch只能判断一种条件,如果这里仅仅是判断logcode,那没问题,如果需要两种判断,switch就不能满足了,不够灵活。
2、局部静态变量
静态变量其实是没有局部这种说法的,因为它不再栈上,而是在数据区,但是我们却可以通过这种方式来限制他的作用域,就说我可以在不同的作用域定义相同的静态变量,这样更加利于抽象。
为什么不用全局变量?因为全局变量要定义在函数外面,这样做不方便抽象,每添加一个过滤就要手动添加一个全局变量,不方便。

宏的封装
c代码
#define BEGIN_FILTER \
unsigned short LogCode = 0;\
unsigned int TimeStamp = 0;\
int ret = FALSE;\
LogCode = *(unsigned short*)(Msg + 2);\
TimeStamp = *(unsigned int*)(Msg + 4);\
do\
{

#define FILTER_LOG(logid, duration) \
if(logid == LogCode)\
{\
static unsigned int LastTimeStamp = 0;\
ret = IsFilterLog(TimeStamp, &LastTimeStamp, duration);\
break;\
}

#define END_FILTER \
}while(0);\
return ret;

将一个完成的功能拆分成三个宏的组合,抽象出变化的和不变的部分,后续添加删除过滤数据包仅仅会用到第二个宏。
更高的拓展性,如果需要其他样式的判断,那么只需要性添加一种宏就好了,比如后面我需要组装自定义数据包,就添加了一种宏
#define CUSTOM_PKT(logid, CustomPackagefun, IsFilter) \
if (FILTER_LOG1 == LogCode)\
{\
CustomPackagefun(Msg);\
ret = IsFilter;\
}
*/

#define FILTER_LOG0 0x5079U
#define FILTER_LOG1 0x5160U
#define FILTER_LOG2 0x5060U

#define BEGIN_FILTER \
 unsigned short LogCode = 0;\
 unsigned int TimeStamp = 0;\
 int ret = FALSE;\
 LogCode = *(unsigned short*)(Msg + 2);\
 TimeStamp = *(unsigned int*)(Msg + 6);\
 do\
 {

#define FILTER_LOG(logid, duration) \
  if(logid == LogCode)\
  {\
   static unsigned int LastTimeStamp = 0;\
   ret = IsFilterLog(TimeStamp, &LastTimeStamp, duration);\
   break;\
  }

#define END_FILTER \
 }while(0);\
 return ret;


int IsFilterLog(unsigned int TimeStamp, unsigned int *pLastTimeStamp, unsigned int Duration)
{
 int Counter = 0;
 if (0 == *pLastTimeStamp)
 {
  *pLastTimeStamp = TimeStamp;
  return FALSE;
 }

 Counter = TimeStamp - *pLastTimeStamp;
 *pLastTimeStamp = TimeStamp;

 Counter = Counter * 1.25;
 if(Counter >= Duration)
 {
  return FALSE;
 }
 return TRUE;
}

int IsFilterLogs(char* Msg)
{

 BEGIN_FILTER
  FILTER_LOG(FILTER_LOG0, 500)
  FILTER_LOG(FILTER_LOG2, 200)
 END_FILTER
}

 

0 0
原创粉丝点击