织梦CMS - 轻松建站从此开始!

罗索

CPackage

jackyhwei 发布于 2013-08-01 18:48 点击:次 
我刚刚更新完CPakcage类的时同事正在使用Google Protocol Buffer,我也去体验了一把,粗浅的看,protocol buffer使用工具对协议结构加壳,提供给用户现成的操作接口,序列化和反序列化简便了不少,只是源码还需要阅读一段时间,对于协议结构字段的拼装方式一时还不确定
TAG:

这是一篇介绍协议类的文章。

    C编码的时候老师给我们讲socket通讯,将通讯流程确定为几个阶段:初始化包、打包、发包、收包、解包、处理包。其中所谓的包就是一个结构体,包含了需要传输的字段。

    具体来讲,首先将结构体成员初始化完毕赋予相应的数值或者字串,其次将这个结构体各成员拼组到一个buffer中,发送方使用某种网络协议、比如socket发到接收方,接收方接收到数据之后将buffer中的字段依次解析到相应的结构体中,最后对这个结构体的数据进行处理。

    C编码的时候牵扯到几个基本接口:

    1. Init()初始化结构体,有时候还需要为结构体成员申请空间。

    2. Pack()将结构体成员依次拼装到buffer中,对于字串数据需要拼装字串长度和字串内容,对于整型数据需要变换字节序。如果在Init中申请过空间需要将其释放

    3. Send()发送方调用某种网络协议接口发送数据,osp中可以调用osppost或者post发送

    4. Recv()接收方调用某种网络协议接口接收数据,ospInstanceEntry接收消息。

    5. Unpack()接收方根据消息类型将buffer中的数据解析到相应的结构体中,或许又要申请空间,尤其当这个结构体中包含聊天信息等不定长字串时

    6. Deal()接收方接收到消息对消息进行处理,osp中对不同的消息进行不同的处理。

程序员偷偷懒简化结构体结构,结构体字串成员直接使用数组,pack直接将结构体memcpybuffer中或者直接发送结构体,大小为sizeofstructure),unpack直接将接收到的数据memcpy到结构体中。很明显这样并不规范。可是用那么规范的流程来处理这些数据又显得过于累赘、繁琐、耗费精力。而且要对每个协议结构进行重复的类似的操作。

原先工作编码,在协议结构处理这方面没有看到多大的需求,所以简化这个处理流程的想法也就没有付诸实施。最近在做demo时,简化流程出现了需求,在qq中涉及到多个协议结构,对每个协议结构进行类似的打包解包操作,实在耗费时间,所以我写了CPackage类来简化操作。

    CPakcage类支持一系列的操作,

    1. 包括管理一个buffer并且根据用户添加的字段自动更新buffer大小,在处理buffer时处理了内存碎片的问题,其实很简单,buffer的扩张分级增长即可;

    2. 对用户经常使用的基本数据类型提供简化接口,比如WriteU8ReadU8WriteU64ReadU64,在对这些基本数据类型提供支持的同时也支持分网络字节序和本地字节序存储两种方式;

    3. 提供两种基本字串结构的支持,WriteShortStringReadShortStringWriteStringReadString,这两种字串结构存储结构式|u16|u8*||u32|u8*|

    4. 提供writeread等基本接口供用户自行操作buffer以及GetBuf等获取buffer等接口

    5. 提供了packunpack两个纯虚函数供派生类实现打包和解包操作

    CxxPackage就是具体的协议类,它继承自CPackage,提供结构成员,提供packunpack的实现,提供两个构造函数实现,一个构造函数用于打包(调用pack),一个构造函数用于解包(调用unpack)。用户可以添加其他函数以支持特定功能。具体实现后边代码介绍。

协议类的结构图:

举个具体的例子:

  1. class COMMON_API CLoginPackage : public CPackage 
  2.  
  3.  
  4. public
  5.  
  6.          u32 m_dwContexLen; 
  7.  
  8.          u32 m_dwNodeid; 
  9.  
  10.          u16 m_wUsrIdLen; 
  11.  
  12.          u8  m_szUsrId[USERINFO_LENTH]; 
  13.  
  14.          u16 m_wUsrPwdLen; 
  15.  
  16.          u8  m_szUsrPwd[USERINFO_LENTH]; 
  17.  
  18. public
  19.  
  20.          CLoginPackage(const u8* szBuf, u32 nLen) : CPackage(szBuf, nLen) 
  21.  
  22.         { 
  23.  
  24.                  memset(m_szUsrId, 0, USERINFO_LENTH); 
  25.  
  26.                  memset(m_szUsrPwd, 0, USERINFO_LENTH); 
  27.  
  28.                  Unpack(); 
  29.  
  30.         } 
  31.  
  32.          CLoginPackage( const u8* szId, u16 nIdLen, const u8* szPwd, u16 nPwdLen, 
  33.  
  34.                    u32 nNodeid = 0) 
  35.  
  36.         { 
  37.  
  38.                  memset(m_szUsrId, 0, USERINFO_LENTH); 
  39.  
  40.                  memset(m_szUsrPwd, 0, USERINFO_LENTH); 
  41.  
  42.                  m_wUsrIdLen = nIdLen; 
  43.  
  44.                  m_wUsrPwdLen = nPwdLen; 
  45.  
  46.                  m_dwContexLen = sizeof u16 + m_wUsrIdLen + 
  47.  
  48.                            sizeof u16 + m_wUsrPwdLen + sizeof u32; 
  49.  
  50.                  memcpy(m_szUsrId, szId, nIdLen); 
  51.  
  52.                  memcpy(m_szUsrPwd, szPwd, nPwdLen); 
  53.  
  54.                  m_dwNodeid = nNodeid; 
  55.  
  56.                  Pack(); 
  57.  
  58.         } 
  59.  
  60.          ~CLoginPackage(){} 
  61.  
  62. //在协议处理时或许需要更新协议结构的某个字段,我们又不希望定义新的协
  63. //议结构变量进行初始化那么可以自行编写这样的接口来更新协议结构中的字段 
  64.  
  65.          virtual s32 UpdateNodeid( u32 dwNodeid ) 
  66.  
  67.         { 
  68.  
  69.                  m_dwNodeid = dwNodeid; 
  70.  
  71.                  Seek(sizeof u32, SEEK_SET); 
  72.  
  73.                  return WriteU32(dwNodeid); 
  74.  
  75.         } 
  76.  
  77. private
  78.  
  79.          virtual s32 Pack() 
  80.  
  81.         { 
  82.  
  83.                  WriteU32(m_dwContexLen); 
  84.  
  85.                  WriteU32(m_dwNodeid); 
  86.  
  87.                  WriteShortString(m_szUsrId, m_wUsrIdLen); 
  88.  
  89.                  WriteShortString(m_szUsrPwd, m_wUsrPwdLen); 
  90.  
  91.                  return 0; 
  92.  
  93.         } 
  94.  
  95.          virtual s32 Unpack() 
  96.  
  97.         { 
  98.  
  99.                  ReadU32(&m_dwContexLen); 
  100.  
  101.                  ReadU32(&m_dwNodeid); 
  102.  
  103.                  m_wUsrIdLen = ReadShortString(m_szUsrId, USERINFO_LENTH); 
  104.  
  105.                  m_wUsrPwdLen = ReadShortString(m_szUsrPwd, USERINFO_LENTH); 
  106.  
  107.                  return 0; 
  108.  
  109.         } 
  110.  
  111. }; 

    打包和解包的代码是不是简化了很多呢。

    我刚刚更新完CPakcage类的时同事正在使用Google Protocol Buffer,我也去体验了一把,粗浅的看,protocol buffer使用工具对协议结构加壳,提供给用户现成的操作接口,序列化和反序列化简便了不少,只是源码还需要阅读一段时间,对于协议结构字段的拼装方式一时还不确定,而且对于并不大的项目,我选择使用更简单的方法。还有tinyxml,这是一个不错的工具,虽然效率比不上protocol buffer,但是它也提供了丰富的key=value的构造和解析方法。同事积极使用流行的工具值得学习。CPakcage类的想法是简化协议包的构造和解析步骤,它没有提供那么多的功能,没有提供一种协议规范,应用范围在项目中网络传输模块的打包和解包步骤。CPackage效率还是很不错的,它具有微型身板儿。

    保存、传输、交换数据,它能满足日常项目需求,在此把这个工具分享给同事,可以自由分发修改和保存,注明发源地哦。

 

(田端瑞)
本站文章除注明转载外,均为本站原创或编译欢迎任何形式的转载,但请务必注明出处,尊重他人劳动,同学习共成长。转载请注明:文章转载自:罗索实验室 [http://www.rosoo.net/a/201308/16711.html]
本文出处:科达微博 作者:田端瑞 原文
顶一下
(0)
0%
踩一下
(0)
0%
------分隔线----------------------------
发表评论
请自觉遵守互联网相关的政策法规,严禁发布色情、暴力、反动的言论。
评价:
表情:
用户名: 验证码:点击我更换图片
栏目列表
将本文分享到微信
织梦二维码生成器
推荐内容