首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 网络游戏 >

说说游戏服务器,该怎么处理

2012-02-21 
说说游戏服务器这是一个纯技术贴,以我做的mansterSLS作为基础,讲述该如何做一个mmorpg游戏服务器。最近心情

说说游戏服务器
这是一个纯技术贴,以我做的mansterSLS作为基础,讲述该如何做一个mmorpg游戏服务器。最近心情不好写到重新入职为止。
所有最新的代码可以在https://sourceforge.net/projects/monstersls/ 目录code,svn下载。
说到网游服务器是最近火起来的,但最初的网游服务器几乎和单机游戏一样的古老那就是mudos。mudos是一个通过文字交流的古老的逻辑系统,有点类似聊天机器人,可以根据不同的客户端命令做出相应的回复,使用户维持在一个自我虚幻的环境,跟着故事情节的发展得到许多不同的命运体验。
游戏服务器处理游戏的逻辑部分,为啥不是在客户端呢?原因是游戏是一个完整的世界,所有事件都发生在这个世界里。既然是一个完整的世界那么这个世界发生的事件就要持续完整。这样所有事件都要记录在服务器供理论上所有客户端去查询。另一原因就是防止客户端篡改游戏世界的数据。请注意wow的客户没有加壳和任何通常的防止黑客的手段为什么呢?因为所有游戏世界的数据和行为都是发生在服务器。客户端的指令要经过逻辑判断,不合逻辑的指令会被判失败。一个简单的例子普通攻击指令执行过程大致是,客户端通过服务器查询看到某人,给服务器发送攻击指令,服务器计算攻击的结果,给客户端和他攻击的目标发送结果,并在服务端保存对用的数据。这里无论通过任何客户端都可以给服务器发送指令甚至是模拟器。服务器会先判断一系列的先决条件,例如攻击距离,对方是否在线等等。通过判断后计算攻击结果,这里一系列的过程客户端是无法更改的全部在服务端完成,并把这些数据共享给对应的客户端。这里我们可以看到在客户修改这些数值没有任何意义,服务判断的依据不是客户端上保存的数据。
到这里我们了解了游戏服务器就是一个大的数据库,这个数据库的特征描述如下:
1,高度并发的读取和写入。
2,数据字段不固定,可能在任何时刻增加或减少。
3,不需要模糊查询的操作,所有数据查询都是对象为基础。
等等剩下的还没有想到。
不过单从上面几点商用数据库可以pass了,即使号称对象数据库的PostgreSQL也不行,数据库的一大弊病就是为了模糊查询需要所有对象共享数据字段,这样即使某个数据不使用某个字段也要共享。会浪费大量的数据空间。游戏里面对象之间的字段也完全没有共性可言。
例如npc是一个对象,椅子也是一个对象,如果按hp,mp排序,要买椅子是hp,mp是零,要么是一个非常大的数值。因为椅子就没有hp,mp。如果npc和椅子放在数据库一个表里面椅子就要浪费mp,hp的两个段值。

C/C++ code
    typedef struct dobject    {        map<string, string> data;        ///for share, only net object using        uintptr_t index;        intptr_t x,y,z;        size_t stamp;        list<uintptr_t> view;        void* psp;    }DOBJECT, *PDOBJECT;

上面代码是我在游戏里对象的定义,由一个动态增加的map段存储游戏里的逻辑数据。
下面讲到的数据和其他的系统相关会在稍后说到其他系统的时候详细介绍
例如mp,hp,物品,任务等等,
index是socket的索引在讲解网络系统的时候会讲到,
x,y,z是对象在空间的坐标,过段时间会加上方向。
stamp,是时间戳为移动加的。
view,是当前可见对象列表。
psp,是当前对象在空间矩阵的位置。
C/C++ code
    typedef struct tobject    {;    public:        uintptr_t id;        PDOBJECT data;        pthread_mutex_t hmutex;    }TOBJECT, *PTOBJECT;

这个结构是我称为cell的结构,是一个静态数组结构的一部分。静态数组结构在服务器被普遍使用目的是通过一个全局地址指针可以快速查到相应的数据结构。因为地址指针是全局静态分配的任何情况下都不会访问失败,是对线程下交换数据最快的方式。我们看到这个结构有3部分组成,第一个是id是一个自增加整数值,每次给cell赋值新的对象都会加一,以区分被销毁的旧对象。humtex是互斥锁为了安全的访问cell内的数据对象,data指向的就是对象。
一个对象的创建的过程如下
C/C++ code
uintptr_t OBJECT::ObNew(char* obid, uintptr_t index){    PDOBJECT ob = new DOBJECT;    ob->index = index;    ob->psp = 0;    ob->stamp = 0;    ///add ob to g_obmap    uintptr_t nob=0, no=0;    for (size_t cursor = 0; cursor < g_maxobj; cursor++)    {        LOCK(g_obmap[cursor].hmutex, OBJECT::ObNew);        if (NULL == g_obmap[cursor].data)        {            g_obmap[cursor].data = ob;            nob = (uintptr_t)&(g_obmap[cursor]);            sprintf(obid, "%p#%u", &g_obmap[cursor], ++g_obmap[cursor].id);            no = 1;        }        UNLOCK(g_obmap[cursor].hmutex, OBJECT::ObNew);        if (no)break;    }    return (uintptr_t)nob;}

第一行new一个新对象,为什么不用malloc呢?因为我要使用map!对不起,我对C的狂热还不深。接下来给这个对象赋初始值,然后循环全局的cell,找到一个最近为空的cell,把刚刚创造的对象放到cell里面。使用前要锁住cell对象,lock和unlock是两个宏。
C/C++ code
///if lock or unlock fail all is unacceptable#define LOCK(mutex, fun) if(pthread_mutex_lock(&mutex) != 0)\{\    Logf(#fun "lock fail\r\n");\    exit(0);\}#define UNLOCK(mutex, fun) if(pthread_mutex_unlock(&mutex) != 0)\{\    Logf(#fun "unlock fail\r\n");\    exit(0);\}

调用pthread_mutex_lock锁住互斥锁,你也许会问你的工程不是vc的吗?这个函数是linux?这是为了避免使用#define宏定义夸平台,所有的代码尽量使用标准C和C++语法避免,因为线程是平台相关的使用了一个了跨平台的win32版本的pthread库方便代码移植到lnux。如果这两个函数失败会写log后结束程序也就是这两个函数在运行过程中不能失败。

接下来我们看
C/C++ code
sprintf(obid, "%p#%u", &g_obmap[cursor], ++g_obmap[cursor].id); 


这个是在lua中使用的对象表示,在lua中对象是由地址和id组成的字符串,Lua部分我们稍后在讲。

C/C++ code
int OBJECT::ObDelete(const char* obid){    PTOBJECT tob = GET_OBJ(obid);    int ret = 0;    LOCK(tob->hmutex, OBJECT::ObDelete);    if(NULL != tob->data && tob->id == GET_IND(obid))    {        if (tob->data->index)            CloseIndex(tob->data->index);        delete tob->data;        tob->data = NULL;        ret = 1;    }    UNLOCK(tob->hmutex, OBJECT::ObDelete);    return ret;}

这段代码讲的是对象的销毁,过程和创建相反根据对象字符串得到对象的地址调用cell锁,锁住对象判断cell对象内data是否为空和对象的id是否和当前cell的id是否相同,满足条件的话判断对象是否是一个网络连接对象,如是连接对象调用CloseIndex关闭连接,删除对象并把cell设置成空。
今天到这,以后不定期继续。


[解决办法]
这是一个纯技术贴.....作为基础,讲述该如何做一个mmorpg游戏服务器。最近心情不好写到重新入职为止。

广告贴吧?

LZ现在怎么失业了?

很好奇,是原来的老板不欣赏你,还是你炒了老板?

[解决办法]
支持楼主 今天要睡觉了 明天再仔细看
[解决办法]
支持楼主 今天要睡觉了 明天再仔细看
[解决办法]

[解决办法]
楼主在写什么?没有主线。
[解决办法]
游戏服务器 用C#或者Java开发很方便,主要是享元模式FlyWeight

用Static集合来管理桌子和局面旁观用户,决定哪些信息局部共享,哪些信息全局共享。
[解决办法]
猿来是知识碎片,欢迎记录之,请LZ继续写
[解决办法]
我想听听楼主对IOCP的讲解, 谢谢~

用AcceptEx异步接受客户连接, 还是开线程accept阻塞式接受?
[解决办法]
顶 学习中
[解决办法]
顶~写的很多,支持楼主~~
[解决办法]
看不懂写了什么,也不知道有什么用~
[解决办法]
此贴必须要MARK。
[解决办法]
支持LZ,您的帖子对我太有价值了~
[解决办法]
一直对游戏服务器很迷惑,楼主的帖子让人有点明白了,谢谢

热点排行