4 ClientUser实现
我们为客户端定义了一个代理类ClientUser,该类继承于基类库中的LinkUser,头文件实现如下
#pragma once
#include "LinkUser.h"
#include <string>
#include "ChatProtocol.h"
class ClientUser : public CLinkUser
{
public:
ClientUser();
public:
virtual bool OnMsg(char* msg, int nLen);
virtual bool OnBreak();
public:
bool OnRequestSessionID();
bool OnCreateRoom();
bool OnJoinRoom(PHYHEADER pHeader);
bool OnChatMsg(PHYHEADER pHeader);
int64_t GetSesID(){return m_sesID;}
public:
std::string m_strNickName;
};基类库的TCPSession在会话创立后,根据消息来源创建,调用服务的CreateUser函数,创建了User对象,并将其和Session绑定,后续ClientUser可以通过这个会话和客户端进行消息通信。
OnMsg函数用于处理客户端发来的消息,根据消息类型的不同,分别由下面的OnXXX函数处理。
给客户端发送消息,调用基类函数SendMsg(char* msg, int nLen);
和客户端连接状态异常,端开连接后,会调用函数OnBreak,函数中可以处理一些清理操作。
最后,定义了一个成员变量nickName,用于记录聊天用户的昵称。
下面看看OnMsg函数的具体实现:
ClientUser收到的消息,其消息格式为HYHEADER打头,这个是由基类保证的,业务层可以直接转换使用。
pHeader的wType参数,标识了消息类型,每个消息定义了一个类型。统一定义在ChatProtocol头文件中
先看获取会话ID的请求,因为会话ID在会话创建时已经自动分配,此处可以直接回复客户端
通过自定义的CHYBuffer,拼接了消息头和消息内容。
首先SetHeaderLen设置消息头长度,但此时未分配空间。后面执行AppendFormatString的时候,才真正分配空间,并在数据前面预留出消息头的数据长度。
消息内容是一个json字符串,因为比较简单,直接进行字符串拼接,内容拼接后为{"sesID":"1"}。
消息头是HYHEADER格式,dwLength是消息内容的长度,此处使用了GetDataLen()函数,是指除了SetHeaderLen函数之后的数据长度,也就是我们发送的内容长度。后面再SendMsg时,传入的参数是GetBufLen(),此时获取的长度是整个buf的数据长度,包含了消息头和消息内容。这两个函数略有差异。
wOrigine设置了消息来源,这个后期可以整合到基类中,避免每次设置,有兴趣的同学可以进行优化。
wType设置了回复消息的类型,这里使用了HY_ACK或上请求类型,wType定义的类型为2个字节,因此最大表示范围到65535.
最后,直接在函数中调用基类的SendMsg方法,将消息回复给客户端。
下面再讲一个略微复杂的请求,客户端请求发送消息的处理
请求发送消息的请求,是携带数据内容的,数据紧跟再Header后面,为json格式。
此处引入了github上的json解析类nlohmann/json.hpp,用于解析客户端上传的json数据。
首先将指针偏移到消息头后面,取char指针作为数据起始,解析json中的msg和roomID。
这里直接使用了服务的指针,调用服务中相应的处理方法,当然这里也可以使用其他方式达到相同的目的,并且解除ClientUser和ChatService之间的耦合,不过直接调用指针也没有太坏的影响,且更为直观,如此处理即可。
同步调用了服务的方法,得到返回结果,作为status的参数,发送给客户端,消息发送方式与获取SessionID的相同,此处不再赘述。
CreateRoom和JoinRoom的请求处理,与上面基本相同,不再详细描述,附上代码
Last updated