3d Game Walkman

3d图形渲染,网络引擎 — tonykee's Blog
随笔 - 45, 文章 - 0, 评论 - 309, 引用 - 0
数据加载中……

今天做了一个Struct结构,作为游戏里面的包容器来使用,可以一次发送多个逻辑结构信息了,爽啊!!!

游戏里面的数据,最重要的就是如何组织,常见的包结构就是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 00:21 李侃 阅读(2043) 评论(2)  编辑 收藏 引用 所属分类: 网络模块

评论

# re: 今天做了一个Struct结构,作为游戏里面的包容器来使用,可以一次发送多个逻辑结构信息了,爽啊!!!  回复  更多评论   

直接序列化数据嘛,干嘛那么麻烦
2008-01-24 08:50 | teli

# re: 今天做了一个Struct结构,作为游戏里面的包容器来使用,可以一次发送多个逻辑结构信息了,爽啊!!!  回复  更多评论   

提个建议,不要用摘要方式发文吧?每看一篇文章都要点击链接进来,不方便。
2008-01-25 09:27 | Fox

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