online游戏服务器架构--业务处理架构

简介:

除了网络架构,业务逻辑的处理更加复杂,为了保证实时性,在处理业务逻辑的时候尽量少用搜索技术,而应该用空间换时间,静态数组是不错的选择,业务逻辑的处理架构其实就是消息映射服务器,通过POST_MSG注册一个回调函数,这个回调函数就是处理具体的业务逻辑的,业务逻辑由协议实现,就是两端商量好的约定俗成的东西:

#define POST_MSG(n,h) if (dispatch[n]) { return -1; } else dispatch[n] = (dispatcher_t)h

Shm_push将业务数据从父进程压入对应子进程的共享内存当中,父进程对数据一无所知,然后子进程从shm_pop开始处理历程,其实就是在net_loop中的handle_recv_queue中调用的shm_pop,这是个循环处理的过程。一个switch开关将pop出来的数据进程分类,大致上分成了关闭包,数据包等等,如果是数据包的话就要进入handle_process的流程:

int handle_process(uint8_t* recvbuf, int rcvlen, int fd, int is_conn)

{

int err = 0;

sprite_t* p;

if (is_conn) {

fdsession_t* fdsess = get_fdsess(fd);

if (fdsess) {

fdsess->last_tm = now.tv_sec;

if ( (err = parse_protocol(recvbuf, rcvlen, fdsess)) )

shm_ctl_block_push(&(config_cache.bc_elem->sendq), fd, FIN_BLOCK, 1);

}

} else { //如果是子进程的话,由于它要和数据库代理服务器进行交互,所以也要处理网络连接

if ( (err = worker_handle_net(fd, recvbuf, rcvlen, &p)) && p )

del_sprite_conn(p, 1);

}

return 0;

}

parse_protocol是核心的调用,在经过一些错误判断和处理后直接将处理流路由到dispatch_protocol函数,在说这个函数之前,有一点要注意,在parse_protocol中会从数据头得到一个session,从这个session中可以得到用户的ID,由于所有的登录用户都会由一个叫做sprite_t的解构体表征,而且只要登录后没有退出的时间段里,这个结构体一直都在,系统会将这些结构体放到一个hash中,这个hash的索引其实就是父进程接收的客户端连接的套接字描述符,由于所有的套接字描述符都在父进程处理,因此它们都是唯一的。等到parse_protocol中调用get_sprite_by_fd将之取出,由于是一个:

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;

}

如果说hash是通过fd来唯一索引的原因是因为父进程中套接字连接描述符的唯一性,那么子进程本身也要处理网络连接,比如和数据库代理服务器以及心跳服务器的连接,并且子进程的网络业务处理逻辑和父进程放入共享内存的数据的处理逻辑使用一套框架,如果这些网络连接描述符也加入到hash的话,势必会引起冲突,毕竟父子进程的描述符不必唯一。解决办法就是将请求发往数据库代理服务器的时候连同这个请求的发起者的客户端实体也一并发过去,这样在数据库代理的应答包当中就可以方便的取出原来的客户端实体,这里是用客户端的套结字描述符来作为客户实体标示的,在数据库的应答包当中可以取出来这个描述符fd,然后同样调用get_sprite_by_fd就可以取出关于这个请求的客户端的sprite_t。

总的来说,dispatch_protocol之前的处理逻辑都是和业务协议无关的,仅仅是数据本身以及用户会话实体方面的处理,接下来就是dispatch_protocol了,这个函数里面就开始了特定用户实体的业务协议相关的处理流程了,这个函数最终调用err = dispatch[cmd](p, body, len);,看看dispatch数组:

dispatcher_t dispatch[MAX_PROC_MSG_NUM];

刚才说到的POST_MSG宏的含义就是注册这些回调函数,这个dispatch_protocol函数可以解析数据包的协议类型,然后将请求路由到正确的处理函数中,以一个例子说明,比如一个报名协议的处理函数是race_sign_cmd:

int race_sign_cmd(sprite_t* p, const uint8_t* body, int bodylen)

{

return send_request_to_db(SVR_PROTO_RACE_SIGN, p, 0, NULL, p->id);

}

这个协议没有数据体,仅仅是一个头部,由于在online端无法处理这个和数据相关的请求,下一步就需要将请求进一步转发给数据库代理服务器,也就是send_request_to_db调用。以下就是数据层的处理了,如果online子进程可以处理客户端的清求,那么就会直接返回处理结果,这样就不需要进入数据层了,处理逻辑会朝着刚才说的相反的方向返回,如果进入数据层的话,就有点复杂了。



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


相关文章
|
8月前
|
存储 机器学习/深度学习 数据库
阿里云服务器X86/ARM/GPU/裸金属/超算五大架构技术特点、场景适配参考
在云计算技术飞速发展的当下,云计算已经渗透到各个行业,成为企业数字化转型的关键驱动力。选择合适的云服务器架构对于提升业务效率、降低成本至关重要。阿里云提供了多样化的云服务器架构选择,包括X86计算、ARM计算、GPU/FPGA/ASIC、弹性裸金属服务器以及高性能计算等。本文将深入解析这些架构的特点、优势及适用场景,以供大家了解和选择参考。
1265 61
|
5月前
|
运维 监控 安全
“没服务器了,那我这运维是白干了吗?”——无服务器架构对运维的冲击与转机
“没服务器了,那我这运维是白干了吗?”——无服务器架构对运维的冲击与转机
150 0
|
6月前
|
存储 安全 虚拟化
全面解析服务器虚拟化:云计算时代的核心技术架构
服务器虚拟化是云计算的核心技术,通过资源池化提升IT效率。本文详解其原理、部署优势及在数字化转型中的关键作用,涵盖技术架构、应用场景与选型指南,助力企业构建高效灵活的云环境。
692 0
|
10月前
|
存储 机器学习/深度学习 应用服务中间件
阿里云服务器架构解析:从X86到高性能计算、异构计算等不同架构性能、适用场景及选择参考
当我们准备选购阿里云服务器时,阿里云提供了X86计算、ARM计算、GPU/FPGA/ASIC、弹性裸金属服务器以及高性能计算等多种架构,每种架构都有其独特的特点和适用场景。本文将详细解析这些架构的区别,探讨它们的主要特点和适用场景,并为用户提供选择云服务器架构的全面指南。
1078 18
|
3月前
|
Cloud Native Serverless API
微服务架构实战指南:从单体应用到云原生的蜕变之路
🌟蒋星熠Jaxonic,代码为舟的星际旅人。深耕微服务架构,擅以DDD拆分服务、构建高可用通信与治理体系。分享从单体到云原生的实战经验,探索技术演进的无限可能。
微服务架构实战指南:从单体应用到云原生的蜕变之路
|
弹性计算 API 持续交付
后端服务架构的微服务化转型
本文旨在探讨后端服务从单体架构向微服务架构转型的过程,分析微服务架构的优势和面临的挑战。文章首先介绍单体架构的局限性,然后详细阐述微服务架构的核心概念及其在现代软件开发中的应用。通过对比两种架构,指出微服务化转型的必要性和实施策略。最后,讨论了微服务架构实施过程中可能遇到的问题及解决方案。