前情回顾
前文我们实现了单服务器踢人的逻辑,通过分布式锁锁住登录过程,在这个期间对用户相关的信息进行更改,主要包括用户id对应的serverip, sessionid等。
同时对用户离线消息进行了处理,也是通过分布式锁锁住退出过程,判断此时用户id对应的sessionid是否和本服记录相等,如果不相等则说明有用户异地登录,此时只要退出即可,否则要清理id对应的sessionid以及serverip等信息。
接下来我们实现跨服踢人逻辑
RPC封装
因为跨服踢人,所以要调用Grpc踢人,我们在message.proto中添加踢人消息
1 | message KickUserReq{ |
同时添加服务调用
1 | service ChatService { |
编写bat脚本自动生成, start.bat内容如下
1 | @echo off |
双击start.bat或者在cmd中执行start.bat也可以
执行后可以发现产生了四个文件

跨服踢人示意图
逻辑编写
StatusServer动态分配
StatusServer中修改动态分配server逻辑
1 | ChatServer StatusServiceImpl::getChatServer() { |
注意这里用到了另一个分布式锁,用来控制服务器人数记录
1 | auto identifier = RedisMgr::GetInstance()->acquireLock(lock_key, LOCK_TIME_OUT, ACQUIRE_TIME_OUT); |
ChatServer踢人逻辑
ChatSever中登录逻辑里添加跨服踢人调用
1 | void LogicSystem::LoginHandler(shared_ptr<CSession> session, const short &msg_id, const string &msg_data) { |
注意上面代码,这段代码就是跨服踢人逻辑。
1 | else { |
关于KickUserReq其实是我们在message.pb.h中生成的。但是我们在自己的文件中使用要用作用域messag::, 所以我们在GrpcClient.h中添加声明
1 | using message::KickUserReq; |
以后我们包含GrpcClient.h就可以使用这些类了。
封装rpc踢人
接下来我们封装rpc接口实现踢人逻辑
rpc客户端接口
1 | KickUserRsp ChatGrpcClient::NotifyKickUser(std::string server_ip, const KickUserReq& req) |
rpc服务端接口实现
1 | Status ChatServiceImpl::NotifyKickUser(::grpc::ServerContext* context, |
为了让ChatServiceImpl 获取CServer, 所以我们提供了注册函数
1 | void ChatServiceImpl::RegisterServer(std::shared_ptr<CServer> pServer) |
这个函数在main函数中启动grpc服务前注册即可。
登录数量统计
在StatusServer中利用分布式锁获取登录数量,动态分配Server给客户端,这里我们也要用ChatServer启动和退出时清空登录数量
重新调整ChatServer启动逻辑
1 | using namespace std; |
上面的逻辑有这样一段,要格外注意
1 | //将登录数设置为0 |
这段逻辑是在服务器启动后将对应服务器中连接数清零写入redis,在服务器结束后从redis中删除数量信息,最后关闭Redis连接池
源码
源码地址