集群聊天服务器——逻辑梳理

打印 上一主题 下一主题

主题 862|帖子 862|积分 2586

网络聊天服务器项目,该项目分为4个模块:
  

  • 起首是网络模块:我使用了muduo高性能网络库,解耦合网络与业务之间这两部分代码,可以更加专注与业务的功能开发
  • 其次是服务层模块:我使用了基于C++11的技能比如绑定器和map,绑定器实现了用户发送的消息id范例回调业务功能函数的机制(当网络i/o发送消息哀求后,通过剖析json消息获取消息id 回调业务功能函数)
  • 然后是数据存储模块:我使用了MySQL数据库存储关键的信息(用户账户、离线消息列表、群组信息、好友列表等)由客户端的功能哀求举行增删改查
  以上是单机服务器的模块设计,但是单机服务器的并发数目是有限的,以是我接纳了集群服务器经行并发本领扩展
      4.最后在多台服务器部署,基于Tcp 协议搭建的C/S 通信,以是我使用了Nginx Tcp负载均衡,保持长毗连状态,而且引入Redis 的发布订阅功能实现跨服务器间通信
  

1. 客户端:

1.1. 两个模块:

1.1.1. 负责用户登录、注册、退出功能

作为客户端毗连服务器乐成后的首界面展示:提供以上三种服务
客户端设计模式:主线线程专注于信息的发送、子线程负责接受信息
将具体功能的所需参数举行json(key-value键值对存储文本形式)序列化发送给服务器
个别服务需要服务器返回方法返回值状态信息,(登录乐成、信息注册乐成)?多线程调和实现
由主线程发送后,阻塞获取信号量,子线程此时接受服务器返回的json对象,由json中的服务方法罗列id,分类细化具体的功能实现业务逻辑,将服务方法调用的状态写入最后将信号量开释,主函数则可以通过子线程写入的状态举行下一步工作

登岸乐成后进入功能菜单:
1.1.2. 负责聊天服务器业务功能:添加好友信息、创建群组、参加群组、单人聊天、群组聊天

将功能函数处理为map表形式<存储函数方法名称,方法绑定器>,循环处理客户端的输入的方法哀求,在循环中未使用switch_case而是map+bind回调,顺应于步伐开发中的开闭原则,对修改关闭,对开发扩睁开放;
该部分函数重要处理用户的功能以及输入的参数,封装为json 对象(服务器协商的通信规则:方法罗列id的标识,与方法哀求划一的参数列表)发送给服务器
  1. auto it = commandHandlerMap.find(command);
  2. if (it == commandHandlerMap.end())
  3. //error
  4. // 调用相应命令的事件处理回调,mainMenu对修改封闭,添加新功能不需要修改该函数
  5. it->second(clientfd, commandbuf.substr(idx + 1, commandbuf.size() - idx));
  6. // 调用命令处理方法
复制代码
 
 
2. 服务器:

2.1. 服务器需要处理信息转发、功能性数据的存储、查询、更新服务

解决基于数据库的功能服务标题:MySQL
解决高并发场景下数据收发标题:muduo 静态网络库
解决跨服务器通信标题 :Redis发布订阅标题
解决负载均衡标题:Nginx_基于Tcp长毗连的负载均衡标题
2.2. 重要基于以上内容将服务器分别出:

server、service、db、model、redis、public 六个模块
2.2.1. server——muduo网络:

基于epoll+多线程的机制实现高并发需求
在该模块中设置四个工作线程,其中一个处理毗连回调,在毗连异常的场景下关闭毗连,余下三个线程为工作线程,完成将接收的字符基于json-parse反序列化发送给service,基于服务方法id,回调具体的处理函数
2.2.2. db:

数据库的接口API ,创建初始化、数据库毗连、
数据更新、数据查询query
  1. // 初始化数据库连接
  2. _conn = mysql_init(nullptr);
  3. // 释放数据库连接资源
  4. if (_conn != nullptr)
  5.   mysql_close(_conn);
  6. // 连接数据库
  7. MYSQL *p = mysql_real_connect(_conn, server.c_str(), user.c_str(),
  8.             password.c_str(), dbname.c_str(), 3306, nullptr, 0);
  9. // 更新操作
  10. mysql_query(_conn, sql.c_str())
  11. // 查询操作
  12. mysql_query(_conn, sql.c_str())
  13.     return mysql_use_result(_conn);
复制代码
2.2.3. model:



该模块用来实现用户需求与服务器数据库交互增、删、改、查标题
以举例:
  1. // 添加好友关系,在好友数据表中添加一条记录
  2. sprintf(sql, "insert into friend values(%d, %d)", userid, friendid);
  3. // 返回用户好友列表,联合查询用户表和好友表,将结果插入vector并用返回
  4. sprintf(sql, "select a.id,a.name,a.state from user a /
  5. inner join friend b on b.friendid = a.id where b.userid=%d", userid);
  6. // 删除用户的离线消息,删除离线列表的一条信息
  7. sprintf(sql, "delete from offlinemessage where userid=%d", userid);
  8. // 更新用户的状态信息
  9. sprintf(sql, "update user set state = '%s' where id = %d",/
  10.     user.getState().c_str(), user.getId());
复制代码
2.2.4. redis:

基于Redis发布订阅标题,解决跨服务器通信标题:
初始化发布上下文、订阅上下文,举行毗连、向指定chennel 发布、订阅,结束订阅、断开毗连

2.2.5. service:

设置方法map集合<方法id,方法handler绑定器>
设置用户毗连map集合<用户id,毗连TcpConnectionPtr接口>,将全部方法的罗列值,函数方法绑定器插入map表,毗连Redis服务器、MySQL 数据库
基于具体的方法选择,联合底层存储的用户数据(查询、插入、删除)完成登录、注册、注销用户;
联合model模块下的函数具体联合用户需求美满功能函数;
聊天服务:查询用户的毗连信息,在本服务器时转发聊天信息,不在本台服务器,查抄数据库的用户登岸状态,未登录存储离线信息表,登录则发布到Redis的发布队列
登录标题:(最复杂)
从json对象剖析得到登录id、暗码
在用户信息表中查询该id的所属对象并比对暗码,不划一将封装json返回原因;
划一时查抄登岸状态避免重复登岸,继而更新用户的登岸状态;
在用户登录map中插入其毗连信息;
订阅Redis对该id 为chennel的消息;
打印该用户的离线消息;
将该对象的好友信息封装为vector存储的json序列化文本信息,作为返回的json-response对象key-value 存储的对象之一;群组信息如上;
最后返回最后的json-response序列化内容。
2.2.6. public:

保存服务方法的罗列信息,将每一服务名称与id一一对应



免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

兜兜零元

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表