RELATEED CONSULTING
相关咨询
选择下列产品马上在线沟通
服务时间:8:30-17:00
你可能遇到了下面的问题
关闭右侧工具栏

新闻中心

这里有您想知道的互联网营销解决方案
Teamtalk登录流程详解,客户端和服务器交互流程分析-创新互联

提示:要学习客户端和服务器如何交互, 就是去找它们通信协议中对应命令发送过程。 对于登录过程,对应登录命令就是去分析CID_LOGIN_REQ_USERLOGIN

创新互联服务项目包括蒙阴网站建设、蒙阴网站制作、蒙阴网页制作以及蒙阴网络营销策划等。多年来,我们专注于互联网行业,利用自身积累的技术优势、行业经验、深度合作伙伴关系等,向广大中小型企业、政府机构等提供互联网行业的解决方案,蒙阴网站推广取得了明显的社会效益与经济效益。目前,我们服务的客户以成都为中心已经辐射到蒙阴省份的部分城市,未来相信会继续扩大服务区域并继续获得客户的支持与信任!客户端登录模块

客户端工程一共包含十个项目
在Moudles项目下的 Login文件夹中找到LoginDialog.cpp(有一个_DoLogin()函数) ;在TcpClient文件夹中找到 TcpClientModule.cpp(有一个doLogin()函数),
这两个是最关键的步骤,在_DoLogin(),可以看到

还记得客户端的配置吗?
http://127.0.0.1:8080/msg_server

下边这个函数的调用就是发起http请求的意思
在LoginDlg.cpp 200行处
module::getHttpPoolModule()->pushHttpOperation(pOper);

当Login_server服务器处理了这条http请求(若成功,会将分配给你的msg_server服务器的ip,port, name等信息以json串的格式返回给你)

在LoginDlg.cpp 207行处
module::TTConfig* pCfg = module::getSysConfigModule()->getSystemConfig();
TTConfig对象就保存了服务器返回的msg_server信息(ip, port等)

在上边我们已经得到http请求的回应,此时我们已经有了
在LoginDlalog.cpp中213行可以看到创建了一个LoginOperation(继承自ICallbackOpertaion)对象,通过startOperation()将这个对象当作一个任务放入了一个list待执行队列中, 并为它注册了一个回调函数(不只是登录模块是这样,其他的任务也是以继承ICallbackOpertaion类的方式, 将其子类实例化对象放入这个list链表中,只是这里是LoginOperation这种子类。)
如下:

LoginOperation* pOperation = new LoginOperation(		//去看它的实现, 调用了_DoLogin
			BIND_CALLBACK_1(LoginDialog::OnOperationCallback), loginparam);
		imcore::IMLibCoreStartOperation(pOperation);

在上边我们只是将登录任务放进了待执行队列,那么在哪里调用呢?

在LoginOperation.cpp中48行可以看到doLogin在这里被调用(doLogin里面可以找到发送CID_LOGIN_REQ_USERLOGIN命令的语句)。

先获取msg_server的ip,port信息,在TTConfig结构体内可以查看
module::TTConfig* pCfg = module::getSysConfigModule()->getSystemConfig();
IM::Login::IMLoginRes* pImLoginResp = (IM::Login::IMLoginRes*)module::getTcpClientModule()
		->doLogin(server, pCfg->msgServPort,m_loginParam.csUserName,m_loginParam.password);

doLogin是在processOpertion中调用的,processOpertion是一个重写的函数, 不同的Operation类(这里是LoginOperation)对应着不同功能的processOpertion,可以把它理解为去执行任务(这里指登录任务)

这里要明白,发送消息的前提是建立了连接,doLogin函数中的第一行就是建立连接过程,这个连接和最开始的http连接获取msg_server不一样, http请求是客户端去连接的Login_server,为了获取msg_server信息, 而这次是客户端与msg_server建立连接。

TcpClientModule_Impl.cpp 148行
IMLibCoreConnect(util::cStringToString(linkaddr), port);

简单的理解当你点击登录按钮,会触发_DoLoing()需要做两件事, 先发送http消息请求,Login_server服务器返回给你msg_server服务器信息(ip,port,name),后在doLogin()中去连接msg_server进行一系列的信息验证过程。

服务器接收模块

主要分析, 在哪接收客户端的请求,以及如何为这条连接做负载均衡(将这条连接放到负载最小的msg_server上)。

客户端的请求包含了两部分,第一部分是http请求(用Login_server来接收处理, 目的是给客户端找一个msg_server), 第二部分是具体的命令发送如:CID_LOGIN_REQ_USERLOGIN(用第一步找到的msg_server来接收处理)

抓住主线:
一:在Login_server中接受客户端的http连接

http://127.0.0.1:8080/msg_server

Login_server服务器将负载最小的msg_server服务器信息(ip,port等)以json格式返回给客户端。
二:然后客户端再去连接这个msg_server, 说白了,Login_server只是一个中转站,msg_server才是与客户端一直交流的主要服务器。

首先在longin_server.cpp找, 在118行,我们可以看到longin_server.cpp通过netlib_listen监听了3个端口, 其中的HttpPort(也就是8080端口,就是负责处理登录连接的第一步,处理http请求消息, 登录连接的第二步是与msg_server交互)

netlib_listen就是封装了listen过程,将这个监听套接字(fd)注册到了epoll_wait()中,并且设置了回调函数(http_callback第49行),对比我们以往的C语言编程思维,因为Teamtalk是C++写的,它将所有的套接字(fd)都封装成了一个CBaseSocket对象,并且将这个对象通过map映射在hash表中保存,fd作为key,CBaseSocket对象作为value 当客户端点击登录的时候, 就会触发消息,所以我们需要去找epoll_wait() 在哪,在EventDispatch.cpp中的354行可以找到,当fd有消息的时候,通过我们刚刚说的那个hash映射表,因为key是fd, 我们就可以找到对应的CBaseSocket对象进行一系列处理(Read, Write等)。

登录第一步处理http连接(在login_server上)

当客户端点击登录后(_DoLogin), 服务器的HttpPort(也就是8080端口)对应的监听fd 被触发,这里一定要明白,客户端点了登录按钮后,涉及了两个步骤,先是发送http请求来向Login_server服务器获取负载最小的msg_server服务器的信息(ip,port), 所以首先讨论的是Login_server处理http请求。 通过监听fd找到对应的CBaseSocket对象,进一步调用pSocket->OnRead(); 在OnRead中可以看到_AcceptNewSocket,它的功能就是将这个客户端点击登录的连接接收,分配一个CBaseSocket对象与之(客户端点击登录的连接)绑定,放到全局hash映射表中,并注册到epoll_wait的队列中,在这个函数(_AcceptNewSocket)的最后一行可以看到m_callback(m_callback_data, NETLIB_MSG_CONNECT, (net_handle_t)fd, NULL), 这个m_callback就是一开始为监听fd注册的http_callback函数(在longin_server.cpp中的49行)
这里一定不要搞混了,这个http_callback和上边提到的pSocket->OnRead()完全不是一个东西, 可以把pSocket->OnRead()理解为宏观的所有套接字的统一接口,而http_callback才是对应的套接字(这里指这个监听fd)的具体回调函数。 接着进入http_callback 中可以知道,我们为这条新的登录连接(http连接)注册了回调函数httpconn_callback。 (这里也一定要明白,到这里我们只是接受了http的连接, 还并没有处理http消息,一定要有清晰的逻辑,所有的处理前提都是先建立tcp连接)
至此我们已经成功的接受了这条连接,并且设置了这条连接的回调函数,并将新连接的fd(http请求的连接)加入到了epoll_wait的队列中,重点:此时我们还没有处理客户端发送过来的 http://127.0.0.1:8080/msg_server, 当收到这条信息时, epoll_wait触发fd(客户端点击登录的连接),通过全局hash找到这条连接的CBaseSocket对象,调用pSocket->OnRead(), 在OnRead中可以看到,这次并不是进入的_AcceptNewSocket, 而是直接走的下边的回调函数m_callback, 此时这条连接(客户端点击登录的连接)的回调函数是httpconn_callback(在HttpConn.cpp中36行),通过fd找到对应的连接,注意这里不是CBaseSocket连接,仔细的朋友可以发现每个fd都绑定了两个对象,一个是CBaseSocket对象, 另一个是Conn对象 , 进一步调用pConn->OnRead(); ,这个OnRead和前边说的pSocket->OnRead()不是同一个, 在这个OnRead中我们可以找到 _HandleMsgServRequest(url, content); 这个函数中寻找负载最小的msg_server并将信息(ip,port)以json格式返回给客户端
至此 登录过程的第一步已经完成,我们已经成功将负载最小的msg_server信息返回给客户端了

登录第二步处理客户端登录请求(在msg_server上)

本文主要学习整体流程, 在msg_server上涉及了数据库服务器对客户端的登录信息进行验证,暂不深究。 msg_server上和Login_server一样,当有客户来连接的时候(tcp连接过程),会给这个客户fd绑定一个CBaseSocket对象,和一个Conn对象(Login_server上是CLoginConn对象,msg_server是MsgConn对象)。

当客户端发送CID_LOGIN_REQ_USERLOGIN命令,epoll_wait触发,pSocket->OnRead();

pSocket->OnRead();
m_callback(); //Login_server和msg_server都是一样的接口imconn_callback函数
//在imconn_callback中
pConn->OnRead();	//
//进入OnRead,可以看到
HandlePdu(pPdu);
//Login_server和msg_server不是同一个pConn,并且它们都重写了HandlePdu(pPdu)函数,所以有不同的实现
//在MsgConn.cpp中282行,即可看到对于CID_LOGIN_REQ_USERLOGIN命令的处理。
case CID_LOGIN_REQ_USERLOGIN:
      _HandleLoginRequest(pPdu );
以上就是客户端点击登录按钮, 一直到服务器处理好对应连接的全过程。

你是否还在寻找稳定的海外服务器提供商?创新互联www.cdcxhl.cn海外机房具备T级流量清洗系统配攻击溯源,准确流量调度确保服务器高可用性,企业级服务器适合批量采购,新人活动首月15元起,快前往官网查看详情吧


本文名称:Teamtalk登录流程详解,客户端和服务器交互流程分析-创新互联
链接URL:http://lswzjz.com/article/dcehds.html