myicq-1.0a1服务器代码的一点分析(二)—在线人员管理与内存分配

原创 2003年11月29日 23:02:00

myicq-1.0a1服务器代码的一点分析()—在线人员管理与内存分配

顾剑辉(Solarsoft)

http://solarsoft.126.com

在线人员的管理

upd服务器中,在线人员的管理是必不可少的.其实这种方法也可以用到游戏服务器中.接下去我们来看一下,myicq是怎样管理的.

Myicq采用的是哈希表来管理,哈希表的查找效率是非常高的,到目前是我见的最高效的查找方法,请看myicq中哈希表的实现:

#define HASH_SIZE          (1 << 16)

#define HASH_MASK        (HASH_SIZE - 1)

 

struct HASH {

       ListHead ipport;   //IP和端口

       ListHead uin;     //唯一的ID

};

 

static HASH bucket[HASH_SIZE];//设置""

 

inline int hashfn(uint32 uin)//哈希函数

{

       uin ^= (uin >> 16);

       uin ^= (uin >> 8);

       return (uin & HASH_MASK);

}

 

inline int hashfn(uint32 ip, uint16 port)

{

       int h = (ip ^ port);

       h ^= (h >> 16);

       h ^= (h >> 8);

       return (h & HASH_MASK);

}

并用类SessionHash进行管理看其定义:

class SessionHash {

public:

       static UdpSession *get(uint32 uin);

       static UdpSession *get(uint32 ip, uint16 port);

       static void put(UdpSession *p, uint32 ip, uint16 port);

       static void put(UdpSession *p, uint32 uin);

       static void random(IcqOutPacket &out, int n);

};

UdpSession *SessionHash::get(uint32 uin)

{

       ListHead *pos;

       ListHead *head = &bucket[hashfn(uin)].uin;

 

       LIST_FOR_EACH(pos, head) {

              UdpSession *p = LIST_ENTRY(pos, UdpSession, uinItem);

              if (p->uin == uin)

                     return p;

       }

       return NULL;

}

 

UdpSession *SessionHash::get(uint32 ip, uint16 port)

{

       ListHead *pos;

       ListHead *head = &bucket[hashfn(ip, port)].ipport;

 

       LIST_FOR_EACH(pos, head) {

              UdpSession *p = LIST_ENTRY(pos, UdpSession, ipportItem);

              if (p->ip == ip && p->port == port)

                     return p;

       }

       return NULL;

}

 

void SessionHash::put(UdpSession *p, uint32 ip, uint16 port)

{

       int i = hashfn(ip, port);

       bucket[i].ipport.addHead(&p->ipportItem);      

}

 

void SessionHash::put(UdpSession *p, uint32 uin)

{

       int i = hashfn(uin);

       bucket[i].uin.addHead(&p->uinItem);

}

 

void SessionHash::random(IcqOutPacket &out, int n)

{

       uint16 num = 0;

       uint8 *old = out.skip(sizeof(num));

 

       int start = rand32() & HASH_MASK;

       int i = start;

       do {

              i = ((i + 1) & HASH_MASK);

 

              ListHead *pos, *head = &bucket[i].ipport;

              LIST_FOR_EACH(pos, head) {

                     UdpSession *s = LIST_ENTRY(pos, UdpSession, ipportItem);

                     if (s->status != STATUS_INVIS && s->status != STATUS_OFFLINE) {

                            out << s->uin;

                            out << (uint8) 1;        // online

                            out << s->face;

                            out << s->nickname;

                            out << s->province;

 

                            if (++num >= n)

                                   break;

                     }

              }

 

       } while (num < n && i != start);

 

       old = out.setCursor(old);

       out << num;

       out.setCursor(old);

}

对于这样的管理,我也非常认同,这似乎是最好的方法.

内存分配:

在这里作者是引用了linuxslab的内存分配模式,我先来介绍一下slab,slab是早94年被开发出来的,用与sun microsystem solaris 2.4操作系统中,一般的内存分配如初试化,不用时进行回收.slab引入了一个对象的概念,这个对象其实是存放一组数据结构的内存区,其方法是构造和构析函数,前者用于初始化,后者用于回收.为了避免重复初始化对象,slab分配模式并不丢弃已分配的对象,而是释放但他们依然保留在内存中.再次请求是就不用重新进行初始化了.请看myicq中的代码

struct SLAB;

 

struct OBJ {

       OBJ *next;

       SLAB *slab;

};

 

struct SLAB {

       ListHead item;/*-- 一个cache的所有slab是一个双向链表, 这个是链表指针 */

       int inuse;/*- 这个slab中被使用的对象数 */

 

       OBJ *free; /*-- 指向一个空的对象的指针项, 用于分配空的对象 */

 

};

 

class Cache {//对象进行管理

public:

       Cache(int size, int n);

       ~Cache();

 

       void *allocObj();

       void freeObj(void *p);

 

       static int reclaimAll();

 

private:

       SLAB *newSlab();

       int reclaim(int n = 0xffff);

 

       Cache *nextCache;

       ListHead slabList;

       ListHead *firstNotFull;

 

       int objSize;   //对象大小

      int numObjs;   //对象记数

       int numFreeSlabs;  //Slabs记数

       int slabSize;      //slab大小

 

       static Cache *cacheList;

};

在看代码中我发现几乎所有的内存分配都采用了这种方法,它存在于各个类中的定义,在这里我到认为这种内存分配是否值得,能否保证服务器内存的高效分配呢!因我没有进行测试,所以我不敢断定.我突然想到了一个新的内存管理方法,也是我在关注和分析isee项目时得到的,我们是否可以用isee中的内存管理方法呢?这样是不是可以提高效率,毕竟服务器不能过几天就停机.关于isee中的内存管理可以到http://isee.126.com中去下载,顺便提一句那是一个非常好的学习工程和开发的例子.

服务器设计系列:内存管理

服务器设计人员在一段时间的摸索后,都会发现:服务器性能的关键在于内存。从收包到解析,到消息内存的申请,到session结构内存的申请都要小心处理,尽量减少内存数据copy,减少内存动态申请,减少内存检...
  • zhoudaxia
  • zhoudaxia
  • 2013年11月09日 11:10
  • 3288

服务器后台程序的内存使用问题

目前我开发的一个服务器后台程序存在这么一个问题,由于我的程序要不断的收发消息,并做统计,统计用的是stl的多重map,在统计中会不断的往map里赛数据。但是每次统计后我都会调用clear()去释放内存...
  • bg2bkk
  • bg2bkk
  • 2014年07月14日 01:07
  • 3321

C++内存分配和管理

[导语] 内存管理是C++最令人切齿痛恨的问题,也是C++最有争议的问题,C++高手从中获得了更好的性能,更大的自由,C++菜鸟的收获则是一遍一遍的检查代码和对C++的痛恨,但内存管理在C++中...
  • Jeson_Mei
  • Jeson_Mei
  • 2016年08月16日 11:05
  • 2427

linux内存管理源码分析 - 概述

linux内存管理源码分析 - 概述 本文为原创,转载请注明:http://www.cnblogs.com/tolimit/  http://www.cnblogs.com/tolimit/p...
  • zdy0_2004
  • zdy0_2004
  • 2015年06月05日 22:18
  • 566

uC/OS II内存管理 详细分析

uC/OS II内存管理 详细分析
  • fanwenjieok
  • fanwenjieok
  • 2014年07月12日 18:58
  • 797

Redis源码分析(二十五)--- zmalloc内存分配实现

时间过的很快,经过快1个月的时间学习,本人对Redis源代码的分析已经超过了一半,上几次的学习,我主要的是对于Redis工具类的代码进行了学习。后面的几天我将会学习Redis代码中的一些封装类的实现,...
  • Androidlushangderen
  • Androidlushangderen
  • 2014年10月31日 19:10
  • 4063

内存管理(Linux内核源码分析)

背景本篇博客试图通过linux内核源码分析linux的内存管理机制,并且对比内核提供的几个分配内存的接口函数。然后聊下slab层的用法以及接口函数。内核分配内存与用户态分配内存内核分配内存与用户态分配...
  • hty46565
  • hty46565
  • 2017年07月12日 10:03
  • 364

MFC实现操作系统四种内存分配算法的模拟

作为操作系统的期末作业,和大家分享一下操作系统内存分配算法基于MFC的可视化模拟,本人小菜鸟一只,欢迎大神指正,以后也希望能坚持下来写技术博客的习惯,不断总结不断积累,结交更多兴趣爱好相同的朋友和前辈...
  • CSD1993
  • CSD1993
  • 2014年12月10日 15:06
  • 1491

用jquery,ztree根据角色分配权限

权限jsp /ztree/css/demo.css" type="text/css"> href="/ztree/css/zTreeStyle/zTreeStyle.css" typ...
  • youyou_yo
  • youyou_yo
  • 2015年09月21日 17:14
  • 905

uc/os-iii学习笔记---存储管理(内存管理)

内存管理
  • JosephGodVim
  • JosephGodVim
  • 2016年07月20日 15:47
  • 979
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:myicq-1.0a1服务器代码的一点分析(二)—在线人员管理与内存分配
举报原因:
原因补充:

(最多只允许输入30个字)