online游戏服务器架构—用户登录数据组织

简介:

sprite_t类型的数据结构是核心数据结构,每一个登录用户对应一个,它的初始化在用户登录的时候,此后一直到用户退出或者离线一直保存在系统内存当中,在此过程中该sprite_t数据结构被保存在两个哈希表当中,一个是以用户的id为索引,这个是逻辑相关的,另一个是以此连接的套结字描述符为索引,这个是逻辑无关的:

int parse_protocol(uint8_t *data, int rcvlen, fdsession_t* fdsess)

{

protocol_t pkg;

sprite_t *p, tmp; //tmp是个局部变量,分配于栈上,由于此后的执行续是串行的,也就是说在动态分配sprite_t数据结构于堆上之前并不清除此函数的调用栈帧,因此这里使用局部变量很安全。

int i;

i = 0;

//此处用UNPKG_XX系列解析pkg.len, pkg.ver, pkg.cmd, pkg.id, pkg.ret

p = get_sprite_by_fd(fdsess->fd); //以套结字描述符查找sprite_t数据结构,如果该用户已经登录,那么一定能查找到的,因为用户和online的交互是长连接,如果是登录包,那么肯定查不到,因为这是第一个包

if ((pkg.cmd != PROTO_LOGIN && !p) || (pkg.cmd == PROTO_LOGIN && p) …){

ERROR_RETURN(("pkg error”);

}

if (pkg.cmd == PROTO_LOGIN) {

sprite_t* old = get_sprite(pkg.id); //以id为索引查找该用户是否已经登录

if (old) notify_user_exit(old, -ERR_multi_login, 1); //如果已经登录,那么踢出已经登录的用户

p = &tmp;

memset(p, 0, sizeof(*p));

p->id = pkg.id; //设置用户的id,登录期间一定唯一

p->item_cnt = 0;

p->fd = fdsess->fd; //设置fd,套结字描述符,一定是唯一的

p->fdsess = fdsess;

}

return dispatch_protocol(p, pkg.cmd, data + sizeof (pkg), pkg.len - sizeof (pkg));

}

由此可见,一个sprite_t数据结构连接在两个哈希列表中,一个是套结字描述符为索引的,另一个是用户id为索引的,注意这两个索引都是唯一的索引。每每分配一个sprite_t数据结构都要将之插入到两个哈希表当中,以套结字描述符为索引的查找函数如下:

sprite_t* get_sprite_by_fd(int fd)

{

sprite_t* p = g_hash_table_lookup(all_sprites, &fd);

if ( !p || IS_NPC_ID(p->id) )

return 0;

return p;

}

以用户id为索引的查找函数如下:

static inline sprite_t *get_sprite (uint32_t id)

{

sprite_t *p;

list_for_each_entry (p, &idslots[id % HASH_SLOT_NUM], hash_list)

if (p->id == id)

return p;

return NULL;

}

对于登录包,最终dispatch_protocol会进入到auth_cmd,该函数对用户的一些信息进行一些如MD5之类的验证,然后进入到do_auth函数:

static inline int

do_auth(sprite_t* v)

{

sprite_t* p = add_sprite(v); //该函数将新分配的sprite_t数据结构插入到两个哈希链表当中

notify_user_login(p, 1);

ADD_TIMER_EVENT(p, long_time_min45_in_game, 0, now.tv_sec + 45*60);

ADD_TIMER_EVENT(p, long_time_min10_in_game, 0, now.tv_sec + 10*60);

if (IS_GUEST_ID(p->id)) { //如果是访客的话进入下面流程

enter_map(p, 1, 0); //为访客直接设置地图

rsp_proto_login(p);

return 0;

} else {

return db_get_sprite_with_mail(p);

}

}

sprite_t* add_sprite(sprite_t* v)

{

sprite_t* p = alloc_sprite(v->fd);

*p = *v;

p->stamp = now.tv_sec;

INIT_LIST_HEAD(&p->hash_list);

INIT_LIST_HEAD(&p->map_list);

INIT_LIST_HEAD(&p->timer_list);

list_add_tail(&p->hash_list, &idslots[p->id % HASH_SLOT_NUM]); //插入到以用户id为索引值的哈希链表

return p;

}

static inline sprite_t* alloc_sprite(int fd)

{

sprite_t* p = g_slice_alloc(SPRITE_STRUCT_LEN); //分配一个sprite_t数据结构

p->fd = fd; //初始化一个套结字索引值

g_hash_table_insert(all_sprites, &(p->fd), p); //以套结字描述符为索引插入到全局的哈希链表

++sprites_count;

return p;

}

enter_map是一个很重要的函数,它设置了玩家的地图信息,每一个地图都是一个数据结构map_t,里面包含一个list_head类型的数据结构sprite_list_head,而每一个sprite_t数据结构都有一个list_head类型的map_list,每次初始化完了一个sprite_t之后最终都要调用一个list_add_tail (&p->map_list, &tile->sprite_list_head)将该sprite_t加入到一个map的list当中,这里的list_head就是linux内核中的最常见的list_head数据结构


 本文转自 dog250 51CTO博客,原文链接:http://blog.51cto.com/dog250/1274108



相关文章
|
2天前
|
弹性计算 负载均衡 容灾
应用阿里云弹性计算:打造高可用性云服务器ECS架构
阿里云弹性计算助力构建高可用云服务器ECS架构,通过实例分布、负载均衡、弹性IP、数据备份及多可用区部署,确保业务连续稳定。自动容错和迁移功能进一步增强容灾能力,提供全方位高可用保障。
10 0
|
2天前
LabVIEW使用VI服务器的调用节点将数据传递到另一个VI 使用调用节点(Invoke Node)与通过引用调用节点(Call by Reference)调用VI时有什么差别?
LabVIEW使用VI服务器的调用节点将数据传递到另一个VI 使用调用节点(Invoke Node)与通过引用调用节点(Call by Reference)调用VI时有什么差别?
|
3天前
|
JSON Android开发 数据格式
android与Web服务器交互时的cookie使用-兼谈大众点评数据获得(原创)
android与Web服务器交互时的cookie使用-兼谈大众点评数据获得(原创)
13 2
|
4天前
|
监控 云计算 开发者
探索云计算中的无服务器架构:从概念到实践
无服务器架构作为云计算领域的新兴技术,正在以其高效、灵活的特性吸引着越来越多的开发者和企业。本文将深入探讨无服务器架构的概念及其在云计算中的应用,通过实际案例展示如何利用无服务器架构构建可靠、可扩展的应用系统。
|
13天前
|
监控 安全 持续交付
【专栏】Webhook是服务器主动发送事件通知的机制,打破传统客户端轮询模式,实现数据实时高效传递。
【4月更文挑战第29天】Webhook是服务器主动发送事件通知的机制,打破传统客户端轮询模式,实现数据实时高效传递。常用于持续集成部署、第三方服务集成、实时数据同步和监控告警。具有实时性、高效性和灵活性优势,但也面临安全风险和调试挑战。理解并善用Webhook能提升系统性能,广泛应用于现代软件开发和集成。
|
14天前
|
运维 监控 Serverless
【专栏】无服务器架构,一种云计算模型,让开发者专注编写代码而不必管理服务器(Serverless)
【4月更文挑战第28天】无服务器架构,一种云计算模型,让开发者专注编写代码而不必管理服务器。它基于事件驱动,自动扩展资源并按需计费。优势包括缩短开发周期、优化资源利用、降低成本、提高可用性及简化维护。然而,冷启动延迟、调试困难、性能监控、安全性和学习曲线等挑战仍需解决。随着技术进步,无服务器架构将在科技发展中发挥更大作用。
|
23天前
|
安全 Linux 文件存储
如何在本地服务器部署TeslaMate并远程查看特斯拉汽车数据无需公网ip
如何在本地服务器部署TeslaMate并远程查看特斯拉汽车数据无需公网ip
|
23天前
|
运维 Oracle 关系型数据库
Oracle服务器参数文件:数据王国的“调控大师”
【4月更文挑战第19天】Oracle服务器参数文件,数据库的“调控大师”,掌控着内存管理、进程调度等关键设置。通过参数调整如SGA_MAX_SIZE和PROCESSES,实现性能优化和故障防控。虽然挑战重重,但成功的性能调优带来无尽成就感。它在备份恢复中也扮演重要角色,保障数据一致性与可用性。成为真正的“调控大师”,为数据王国效力!
|
1月前
|
存储 SQL 安全
什么是传统的客户端服务器模式架构
什么是传统的客户端服务器模式架构
30 0
|
1月前
|
JSON 网络协议 开发工具
基于Qt实现的TCP端口数据转发服务器
基于Qt实现的TCP端口数据转发服务器
20 0
基于Qt实现的TCP端口数据转发服务器