Workerman 是一款纯 PHP 开发的开源高性能的 PHP socket 服务器框架。被广泛的用于手机app、移动通讯,微信小程序,手游服务端、网络游戏、PHP聊天室、硬件通讯、智能家居、车联网、物联网等领域的开发。 支持TCP长连接,支持 Websocket、HTTP 等协议,支持自定义协议。拥有异步 Mysql、异步 Redis、异步 Http、异步消息队列等众多高性能组件。
workerman-chat 是一个以 workerman 作为服务器容器,使用 PHP 开发的基于 Websocket 协议的一个可分布式部署的聊天室框架。
workerman-chat 采用 gateway workers 进程模型。gateway只负责网络IO,全异步非阻塞,每个 gateway 进程都可以同时接受上万客户端连接。 workers 采用的是PHP开发者所熟悉的同步模型,并提供了开发者基本的接口 onConnect、onMessage、onClose、sendToClient、sendToAll 等方法。 开发者只要在 onConnect、onMessage、onClose三个方法中添加上自己的业务逻辑即可,开发维护非常简单。
由于采用的是 gateway workers 进程模型,gateway 和 workers 之间是无状态的,gateway 和 workers 可以分别部署在不同的物理机上,所以扩容和升级都非常方便。 workerman-chat 也非常适合游戏后台开发。
因业务需求,要开发一款浏览器端的 IM 应用。 Workerman 系列本身轻便简洁,十分适合用作我们的 WebSocket 服务端。研究了部分资料之后,同时根据 Workerman 官方文档推荐的 workerman 与其他框架的结合方案,并不是内嵌到框架中,而是作为一个独立的应用,与 Api 和 Client 一起处理问题。整体结构如下:
分析具体需求
大体需求如下:
- 多客户端同时在线,数据同步
- 发送端实时接收已读状态更新
- 接收端在一个客户端查看消息后,其他在线客户端去掉未读提醒
其他背景:
- Api 端使用
user-id + token
的校验字段判断用户登录状态。 - 所有数据库操作都在 Api 端也就是 Laravel 中完成, Workerman 只处理 Websocket 请求,不直接操作数据库。
首先,为满足第一个需求,则需要在 Socket Server 端记录在线信息,将 user_id
与 client_id
做一个一对多的关系绑定。此类动态需求,不涉及 MySQL,使用 Redis 处理。
第二和第三个需求,则是通过 Api 和 Socket Server 的协作来完成。一个 “发送 + 已读” 的操作流程如下:
User A: 发送者,在线客户端 Client A1 & Client A2
User B: 接收者,在线客户端 Client B1 & Client B2
WS-Socket: Workerman 提供的 Websocket 服务
WS-API: Workerman 提供的 HTTP 接口服务
API: Laravel 提供的 Api 服务
注:
(1)登录、注册、下限: WS 根据 Client 传来的数据记录 user_id
与 client_id
的一对多关联关系。
(2)所有Socket请求,Client都会携带 user-id & token 参数,然后 WS 将参数传给 API 端校验登录是否有效。
1 | (1)Client A1 : 调用 Api 实现新消息的发送, Api 记录消息,并将消息标记为未读状态。 |
经过以上步骤,整个发送流程完成,符合 Workerman 官方推荐的 workerman 与其他第三方框架的协作模式建议。
功能实现和框架改动
在此过程中,对 Workerman-chat 这个框架做了一些改动:
1. 引入必要的依赖模块
- Redis : 用于记录 User 及其 Client 的一对多关联
2. 代码层面的改动
官方建议使用 workerman-chat
做实时通讯业务,只需要关心 ~\Applications\Chat\Events.php
一个文件中的业务逻辑代码
鉴于实际业务需求,调整自动加载目录文件 ~\vendor\composer\autoload_static.php
1 | public static $prefixLengthsPsr4 = array ( |
这里是为了在 ~/Applications/
目录下添加 ~/Applications/Library/
目录,并在此添加一些常用的工具类。
主要包括:
- Redis 单例实现
- Controller 格式化处理 WS-API 请求
- Config 类处理环境变量和环境隔离(在项目根目录下添加 config.php 并加入 .gitignore,记录一些区分环境的变量参数)
- BaseUtil 基础类,实现一些 Http 请求封装、签名计算和校验等的通用方法。
- UserService 类,实现用户 token 校验和 user-id & client-id 的关联逻辑处理
- SimpleLog 类,文件操作IO,记录一些日志文件。