游戏数据存储设计概述(共享内存)

                                                  游戏数据存储设计概述(共享内存)

                                                           2012-10-03

 

这里只说一下使用共享内存的游戏数据存储方式及设计,比较泛泛地作个介绍。

 

        所谓共享内存存储,是指在内存中开辟一块共享内存,游戏服务器及数据存储程序都能对其进行读写操作,游戏服务器定时把数据写入到共享内存中,数据存储程序定时把数据存入数据库中。它的特点是游戏服务器数据更新迅速,并且尽可能保证了数据的安全。是典型的用内存换效率的做法。

 

1、基本结构

                                          图共享内存存储结构

 

1)数据存储程序启动时,把内存空间开辟好,并且加入除角色数据之外的其它游戏公用数据。

2)游戏服务器启动时,Attach到共享内存,并把共享内存里的数据读出来,对游戏进行初始化(角色数据不读)。

3)角色上线时,登陆程序会从数据库中把角色数据都加载上来,然后转发给游戏服务器,角色取到数据后进行初始化。

4)游戏服务器定时把要存储的数据写入共享内存中。

5)数据存储程序定时把游戏数据写入数据库。

 

2、游戏数据设计

使用共享内存存储方式,从上面结构图可以看出,数据是分块处理的,所以,在游戏开发时,最好能合理地组织游戏中的数据,这样可以更有效的存储数据。

1)存储结构尽量与数据库表结构一致,方便存储及加载,减少表关联操作。例如数据库中的物品表,每一行记录一个物品的数据,那么,游戏中物品结构(struct Item)中的数据可尽量与数据表中的数据列保持一致。

2)数据存储结构与游戏中数据结构分开。存储结构,即共享内存中使用的数据结构,游戏中数据结构,即为游戏服务器中使用的数据结构,上面已说过,游戏服务器定时把数据写入共享内存,那游戏数据结构为什么不直接使用存储结构呢?我们知道,游戏中是有很多数据不需要存储的,但为了数据管理方便,会把这些数据放入数据结构中进行统一管理,比如一个角色的基本数据,游戏中使用的有50个数据,而需要存储的只有30个;这么做还有一个目的,在把游戏数据写入共享内存时,最好不要拷贝整个结构体数据,而是一个数据一个数据写入,这样可以更灵活的控制哪些数据需要更新,哪些可以不更新。

3)游戏中数据、操作分开,数据集中管理。数据与功能逻辑分开,这是程序设计的基本原则之一,比如一个玩家的游戏数据,可以集中进行管理(定义一个大的结构体,内部再对各种数据进行分类),各个功能只保留操作函数,这样对玩家数据的初始化、存储等操作会变得更简单

 

3、共享内存使用

1Linux系统调用

创建:int shmget(key_t key, size_t size, int shmflg)

打开:int shmget(key_t key, size_t size, int shmflg);

关联上:void *shmat(int shmid, const void *shmaddr, int shmflg);

取消关联:int shmdt(const void *shmaddr);

共享内存管理(可关闭操作):int shmctl(int shmid, int cmd, struct shmid_ds *buf);

2Windows API

创建:CreateFileMapping( (HANDLE)0xFFFFFFFFFFFFFFFF, NULL, PAGE_READWRITE, 0, Size, keybuf);

打开:OpenFileMapping( FILE_MAP_ALL_ACCESS, TRUE, keybuf);

关联上:MapViewOfFile(handle, FILE_MAP_ALL_ACCESS, 0, 0, 0);

取消关联:UnmapViewOfFile(MemoryPtr);

关闭共享内存:CloseHandle(handle);

3)共享内存创建及使用

进程1创建一个固定大小的共享内存块(CreateFileMapping),并关联到共享内存块(MapViewOfFile)。其它进程打开共享内存块(OpenFileMapping),并关联到共享内存块(MapViewOfFile)。这样,多个进程就可以对共享内存块进行读写操作,但是在写操作时,需要对共享内存块进行锁定操作,保证数据的一致性。

 

4、共享内存存储的几个问题

1)如何保证数据的安全性。

共享内存是属于系统开辟的内存空间,不属于任一进程,共享内存创建后,会对打开的程序进行计数,在windows系统下,记数为0时,系统会回收内存,而在linux系统下,需要使用ipcrm命令来回收,那怕记数为0,系统也不会自动回收。也就是说,游戏服务器和存储程序只要不同时宕掉,数据就还会在内存中。要保证数据安全性,具体方法有:

在存储程序中加入对游戏服务器的监控,如果发现游戏服务器没反应了,则马上存储所有数据;

存储程序设置启动参数,如果存储程序宕了,可以重新启动时,不从数据库中加载数据,而直接打开共享内存,然后把共享内存的数据回写到数据库中。

2)如何保证数据的一致性

多个进程访问共享内存时,必然会造成脏数据,需要程序员来保证对共享内存操作时的锁定操作,而刚才说过,共享内存属于系统所有,没有相应的加锁函数,所以,只能由程序员自己写一个算法来处理加解锁。

3)如何判断数据的完整性

存储程序对游戏数据进行存储时,如果存储到一半出现了故障,比如停电,这个时候,数据就会不完整。可以在每条数据后面加一个值,代表当前数据存储version,数据每次存储前对version1,如果发现数据第一条与最后一条的version不一致,则可确定数据存储不完整,并且根据version值,很快就能找到存储到哪一条数据时出现了问题

4)如何保证数据的正确性

数据存储时,对重要的数据做CRC校验,并且存储校验值,下次加载数据后,再对那些数据做同样的校验,如果校验值不一致,则可认为数据库中的数据与存储时的数据不一致了。

 

猜你喜欢

转载自blog.csdn.net/qdslp/article/details/9149517