我的玻璃盒子

(转载)一个struct结构,一次发送多个逻辑结构信息

原文:http://www.cppblog.com/tonykee/archive/2008/01/24/41766.html

游戏里面的数据,最重要的就是如何组织,常见的包结构就是type+len+data这样的结构
//所有包的基类型
struct BasePack
{
  unsigned short type;  //类型
  unsigned short len;   //长度
  BasePack();
  unsigned short size();
};
//////////////////////////////////////////////////////////////////////////
//比如这个是登录包结构
struct LoginPack :public BasePack
{
  char username[15];
  char password[10];
  LoginPack();
  unsigned short size();
};
//..还有很多类型的包结构,自己去扩展
//下面这个包结构就很特别了:
这个struct 结构能保存变长的子结构体,也就是结构体的容器,如果一次要发送大量查询的数据,可以用这个容器来装载。结构大致如下:
//////////////////////////////////////////////////////////////////////////
//集合包,这是个很特殊的包,里面的数据是变长的(buffer 将作为子包的首指针)
//当然也有个上限,只不过和StringPack一样,每次发送的数据量不固定,并不一定是包体的长度,
//使用这个包的注意事项:1.如果用tcp,总长不要超过4096, 如果用udp总长不要超过1024(安全指数)
//                      2.一般一个包不会共享给多个线程来处理,而且都是临时拼发,并未考虑线程安全
struct CollectionPack:public BasePack
{
  unsigned short mSubPackCount;   //子包的数量

  char buffer[4096];           //最大限度的包长度,做缓冲

  CollectionPack();

  //清除CollectionPack里面的内容
  void clear();

  //得到子包的数量
  unsigned short getSubpackCount();

  //添加子包,添加是否成功,集合包的大小,默认不超过MTU的大小,当然如果是TCP传输,则没有这个限制,最大可以是4096
  bool   append(BasePack &pack,  unsigned short  maxsize=1500);

  //本集合包的总长度
  unsigned short size();

  //重载数组运算符,这样就可以数组迭代的方式访问子包了,不过用索引迭代没有next迭代的效率高
  BasePack *operator[](int idx);

  //p迭代的指针,返回当前取出来的包的指针使用方法如下:
  //   BasePack *p = 0;
  //while(collection.next(&p))
  //{
  //  p就是当前你找到的包了
  //}
  BasePack * next(BasePack ** p);
};
CollectionPack::CollectionPack()
{
memset(buffer,0, 4096);
type = COLLECTION_PACK;
mSubPackCount = 0;
}

//清除CollectionPack里面的内容
void CollectionPack::clear()
{
mSubPackCount = 0;
memset(buffer,0, 4096);
}

//得到子包的数量
unsigned short CollectionPack::getSubpackCount()
{
return mSubPackCount;
}

//添加子包,添加是否成功
bool   CollectionPack::append(BasePack &pack, unsigned short maxsize)
{
unsigned int currentlen = size(); //当前整个包的长度
unsigned int psize = pack.size(); //即将要加入的包的长度

if(psize + currentlen > maxsize || psize + currentlen > SESSION_BUFFER_LONGTH)
{
  return false; //不能够再装了
}

int len  = size() - 6;

memcpy(buffer + len, &pack,  pack.size());

//StringPack *p = (StringPack *) (buffer + len);
mSubPackCount ++;
return true;
}

//本集合包的总长度
unsigned short CollectionPack::size()
{
len = 0;
for(unsigned short i = 0; i < mSubPackCount; i ++)
{
  BasePack * p = (BasePack *) (buffer + len);
  len += p->size();
}
len += 6;     //(type len  SubPackNum 共6个字节)
return len;
}

//重载数组运算符,这样就可以数组迭代的方式访问子包了,不过用索引迭代没有next迭代的效率高
BasePack * CollectionPack::operator[](int idx)
{
if(idx < 0 || idx >=mSubPackCount)
{
  return 0; //下标越界
}

int ln = 0;
for(unsigned short i = 0; i < mSubPackCount; i ++)
{
  BasePack * p = (BasePack *) (buffer + ln);

  if(idx == i)
   return p;
  else
   ln += p->size();
}

return 0;
}

//p迭代的指针,返回当前取出来的包的指针使用方法如下:
//   BasePack *p = 0;
//while(collection.next(&p))
//{
//  p就是当前你找到的包了
//}
BasePack *  CollectionPack::next(BasePack ** p)
{
char *cur = 0;

if((*p)==0)
  cur = buffer;
else
  cur = (char *)(*p);

//指针后移,定位到下一个包的位置
(*p)=(BasePack *)(cur + ((BasePack *)cur)->size());

if((*p)->type == 0)
  return 0; //没有类型为0类型的包,如果为0,显然是到末尾了
else
  return (*p);
}

有了以上这个容器,要把一些小包组合起来一起发送就非常方便了,但是组合的时候,还是要考虑不能超出上限范围的
不过在真实的游戏服务器里面,包不一定是采用结构体的方式来发送的,有的是把对象串行化成为字节流的方式来发送。
我觉得这样比较麻烦,要encoding decoding,效率调试都不方便,直接法结构体,高效,简单,可就是不太安全。

posted on 2008-01-24 16:28 深蓝色系统 阅读(202) 评论(0)  编辑 收藏 引用


只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   博问   Chat2DB   管理


导航

<2009年8月>
2627282930311
2345678
9101112131415
16171819202122
23242526272829
303112345

统计

常用链接

留言簿(75)

随笔分类

随笔档案

文章分类

文章档案

搜索

最新评论

阅读排行榜

评论排行榜