在分析msg_server的源码之前,我们先简单地回顾一下msg_server在整个服务器系统中的位置和作用:
各个服务程序的作用描述如下:
从上面的介绍中,我们可以看出TeamTalk是支持分布式部署的一套聊天服务器程序,通过分布式部署可以实现分流和支持高数量的用户同时在线。msg_server是整个服务体系的核心系统,可以部署多个,不同的用户可以登录不同的msg_server。这套体系有如下几大亮点:
1. login_server可以根据当前各个msg_server上在线用户数量,来决定一个新用户登录到哪个msg_server,从而实现了负载平衡;
2. route_server可以将登录在不同的msg_server上的用户的聊天消息发给目标用户;
3. 通过单独的一个数据库操作服务器db_proxy_server,避免了msg_server直接操作数据库,将数据库操作的入口封装起来。
在前一篇文章《TeamTalk源码分析(四) —— 服务器端db_proxy_server源码分析》中,我介绍了每个服务如何接收连接、读取数据并解包、以及组装数据包发包的操作,这篇文章我将介绍作为客户端,一个服务如何连接另外一个服务。这里msg_server在启动时会同时连接db_proxy_server,login_server,file_server,route_server,push_server。在msg_server服务main函数里面有如下初始化调用:
其中每个连接服务的流程都是一样的。我们这里以第一个连接file_server为例:
模板函数serv_init展开参数后实际上是调用CFileServConn->Connect(),我们看这个函数的调用:
在这个函数里面创建连接socket,将该socket加入全局map g_file_server_conn_map中保存,map的key是socket句柄值,值是当前连接对象CFileServConn的指针。注意这里设置了回调函数imconn_callback。我们来看netlib_connect()实际连接的代码:
注意这里有以下几点:
1. 将socket设置成非阻塞的。这样如果底层连接函数connect()不能立马完成,connect会立刻返回。
2. 将socket的状态设置成SOCKET_STATE_CONNECTING。
3. AddBaseSocket(this)将该socket加入一个全局map中。
4. 关注该socket的所有事件(SOCKET_ALL)。
因为socket是非阻塞,所以connect可能没连接成功,也会立即返回。那连接成功以后,我们如何得知呢?还记得上一篇文章中介绍的主线程的消息泵吗?TeamTalk每个服务的主线程都有一个这样的消息泵:
当socket连接成功以后,该socket立马会变的可写。此时会触发第5步中的可写事件:
由于该socket的状态是SOCKET_STATE_CONNECTING,会走第一个if分支。在不出错的情况下,以参数NETLIB_MSG_CONFIRM调用之前设置的回调函数imconn_callback。
这次走pConn->OnConfirm();分支,由于pConn实际是CImConn的子类对象,根据C++多态性,会调用CFileServConn的OnConfirm()函数:
连接上file_server后,msg_server会立即给file_server发一个数据包,以获得file_server的ip地址等信息。
这就是msg_server作为客户端连接其他服务的流程。与这些服务之间的连接都对应一个连接对象:
file_server CFileServConn
db_proxy_server CDBServConn
login_server CLoginServConn
route_server CRouteServConn
push_server CPushServConn
而且,和连接file_server一样,msg_server在连接这些服务成功以后,可能会需要将自己的一些状态信息告诉对方:
再来提一下,心跳包机制,和上一篇文章中介绍个与db_proxy_server一样,都是在定时器里面做的,这里不再赘述了,简单地贴出与file_server的心跳包代码吧:
在注册的定时器回调函数里面调用CFileServConn::OnTimer函数:
接下来的就是每个连接上的业务处理代码了,主消息泵收到数据后触发OnRead函数,然后收取数据解包,然后根据包的命令号处理包,所以每个连接对象根据自己的业务都有一个HandlePdu()函数,例如CFileServConn的:
当然有些数据包,msg_server直接自己装包应答就可以了。有些必须发到其他服务进行进一步处理,比如登录请求,发给db_proxy_server拿到mysql中校验用户名和密码,db_proxy_server校验完成后,再应答msg_server,msg_server再应答客户端。
这大概就是msg_server服务的结构和源码了吧。具体业务代码你可以查看每个连接对象的HandlePdu()函数来看具体的流程细节。
需要指出的是:连接服务器、接受连接、收取数据解包、发送数据这四个模块是一个完整的网路库必须具有的东西。这篇文章和上一篇文章完整地介绍了这四个模块,而TeamTalk的实现手法也是目前主流网络库的通用做法。如果从事服务器开发,必须熟练掌握这里面的具体每个细节。而teamtalk服务器这种分布式架构设计的思想也是非常值得学习和借鉴的。
如果您对服务器开发技术感兴趣,可以关注我的微信公众号『高性能服务器开发』,这个微信公众号致力于将服务器开发技术通俗化、平民化,让服务器开发技术不再神秘,其中整理了将服务器开发需要掌握的一些基础技术归纳整理,既有基础理论部分,也有实战部分。
本网信息来自于互联网,目的在于传递更多信息,并不代表本网赞同其观点。其原创性以及文中陈述文字和内容未经本站证实,对本文以及其中全部或者部分内容、文字的真实性、完整性、及时性本站不作任何保证或承诺,并请自行核实相关内容。本站不承担此类作品侵权行为的直接责任及连带责任。如若本网有任何内容侵犯您的权益,请及时联系我们,本站将会在24小时内处理完毕,E-mail:xinmeigg88@163.com
本文链接:http://www.ksxb.net/tnews/4379.html