当前位置: 首页 > article >正文

GatewayWorker框架的详解和应用

一、介绍

1. 简介

GatewayWorker基于Workerman开发的一个项目框架,用于快速开发TCP长连接应用,例如app推送服务端、即时IM服务端、游戏服务端、物联网、智能家居等等

GatewayWorker使用经典的Gateway和Worker进程模型。Gateway进程负责维持客户端连接,并转发客户端的数据给BusinessWorker进程处理,BusinessWorker进程负责处理实际的业务逻辑(默认调用Events.php处理业务),并将结果推送给对应的客户端。Gateway服务和BusinessWorker服务可以分开部署在不同的服务器上,实现分布式集群。

GatewayWorker提供非常方便的API,可以全局广播数据、可以向某个群体广播数据、也可以向某个特定客户端推送数据。配合Workerman的定时器,也可以定时推送数据。

 2. 特性

1、基于Workerman开发
GatewayWorker是基于Workerman开发的

2、基于Gateway、Worker进程模型
GatewayWorker使用经典的Gateway和Worker进程模型。Gateway进程负责维持客户端连接,并转发客户端的数据给Worker进程处理;Worker进程负责处理实际的业务逻辑,并将结果推送给对应的客户端。Gateway服务和Worker服务可以分开部署在不同的服务器上,实现分布式集群。

3、支持分布式部署
GatewayWorker可以非常方便实现分布式部署,Gateway服务和Worker服务都可以分开部署在不同的服务器集群上。并且操作简单、容易扩容、上下线用户无感知。

4、支持高并发
Gateway进程只负责网络IO,Worker进程负责业务逻辑。其中每个Gateway进程可以维持上万的并发连接,多个Gateway进程可以维持数十万甚至百万的并发连接,Gateway集群则可以维持千万级别的并发连接。

5、支持全局广播或者向任意客户端推送数据
GatewayWorker提供非常方便的API,可以全局广播数据、可以向某个群体广播数据、也可以向某个特定客户端推送数据。配合Workerman的定时器,也可以定时推送数据。

6、支持各种应用层协议
WorkerMan接口上支持各种应用层协议,包括自定义协议。同样GatewayWorker也支持各种应用层协议。

7、多协议支持
有时应用客户端所使用的协议不止一种,例如PC网页客户端使用的是WebSocket协议,而手机App使用的是其它协议。GatewayWorker可以非常方便的支持多协议,只需要以不同的协议开不同的端口即可,业务代码无需改动。

8、支持对象或者资源永久保持
WorkerMan在运行过程中只会载入解析一次PHP文件,然后便常驻内存,这使得类及函数声明、PHP执行环境、符号表等不会重复创建销毁,这与Web容器下运行的PHP机制是完全不同的。在WorkerMan中,一个进程生命周期内静态成员或者全局变量在不主动销毁的情况下是永久保持的,也就是将对象或者链接等资源放到全局变量或者类静态成员中则整个进程生命周期内的所有请求都可以复用。例如只要单个进程内初始化一次数据库连接,则以后这个进程的所有请求都可以复用这个数据库连接,避免了频繁连接数据库过程中TCP三次握手、 数据库权限验证、断开连接时TCP四次握手的过程,极大的提高了应用程序效率。

9、高性能
由于php文件从磁盘读取解析一次后便会常驻内存,下次使用时直接使用内存中的opcode, 极大的减少了磁盘IO及PHP中请求初始化、创建执行环境、词法解析、语法解析、编译opcode、请求关闭等诸多耗时过程, 并且不依赖nginx、apache等容器,少了nginx等容器与PHP通信的开销,最主要的是资源可以永久保持,不必每次初始化数据库连接等等, 所以使用WorkerMan开发应用程序,性能非常高。

10、支持HHVM
支持在HHVM虚拟机上运行,可成倍提升PHP性能。尤其是在cpu密集运算业务中,性能非常优异,是PHP Zend虚拟机8倍左右。通过实际压力测试对比,在没有负载业务的情况下,WorkerMan在HHVM下运行比在Zend PHP5.6运行网络吞吐量提高了30-80%左右

11、方便与其它项目集成
针对其它项目,GatewayWorker提供推送非常简单方便的API,可以在任何项目中使用这个API向所有客户端或者特定客户端推送数据,比如在普通Web项目中推送数据。

12、支持代码热更新
可以reload Worker进程实现业务代码更新升级,而不必担心客户端连接会断开,因为客户端连接都由Gateway进程维持。

13、支持长连接
GatewayWorker主要用于长连接即时通讯应用。如游戏服务器、物联网云服务、IM、移动应用等。

  3. 原理

1、Register、Gateway、BusinessWorker进程启动

2、Gateway、BusinessWorker进程启动后向Register服务进程发起长连接注册自己

3、Register服务收到Gateway的注册后,把所有Gateway的通讯地址保存在内存中

4、Register服务收到BusinessWorker的注册后,把内存中所有的Gateway的通讯地址发给BusinessWorker

5、BusinessWorker进程得到所有的Gateway内部通讯地址后尝试连接Gateway

6、如果运行过程中有新的Gateway服务注册到Register(一般是分布式部署加机器),则将新的Gateway内部通讯地址列表将广播给所有BusinessWorker,BusinessWorker收到后建立连接

7、如果有Gateway下线,则Register服务会收到通知,会将对应的内部通讯地址删除,然后广播新的内部通讯地址列表给所有BusinessWorker,BusinessWorker不再连接下线的Gateway

8、至此Gateway与BusinessWorker通过Register已经建立起长连接

9、客户端的事件及数据全部由Gateway转发给BusinessWorker处理,BusinessWorker默认调用Events.php中的onConnect onMessage onClose处理业务逻辑。

10、BusinessWorker的业务逻辑入口全部在Events.php中,包括onWorkerStart进程启动事件(进程事件)、onConnect连接事件(客户端事件)、onMessage消息事件(客户端事件)、onClose连接关闭事件(客户端事件)、onWorkerStop进程退出事件(进程事件)

二、应用

1. 目录结构

├── Applications // 这里是所有开发者应用项目

│   └── YourApp // 其中一个项目目录,目录名可以自定义

│   ├── Events.php // 开发者只需要关注这个文件

│   ├── start_gateway.php // gateway进程启动脚本,包括端口号等设置

│   ├── start_businessworker.php // businessWorker进程启动脚本

│   └── start_register.php // 注册服务启动脚本

│ ├── start.php // 全局启动脚本,此脚本会依次加载Applications/项目/start_*.php启动脚本 │ └── vendor // GatewayWorker框架和Workerman框架源码目录,此目录开发者不用关心

二、Lib\Gateway类提供的接口
既然(默认)在 Events.php 中处理实际的业务逻辑,回调的事件我们已经知道了。那么怎么向客户端发送消息呢?
命名空间 \GatewayWorker\Lib\Gateway 指向的这个 Gateway 类,提供了一组单发、群发和广播的接口,在 Events.php 中向客户端发信的时候就可以使用这个类。它提供的接口非常丰富:
Gateway::sendToAll($data);      // 向所有客户端发送数据
Gateway::sendToClient($client_id, $data);  // 向某个客户端发送数据
Gateway::closeClient($client_id);      // 关闭某个客户端
Gateway::isOnline($client_id);  // 判断某客户端连接是否在线
Gateway::bindUid($client_id, $uid);    // 绑定 uid 与 client_id
Gateway::unbindUid($client_id, $uid);  // 取消 uid 与 某个 client_id 的绑定
Gateway::isUidOnline($uid);      // 某个 uid 是否在线
Gateway::GetClientIdByUid();     // 获取与 uid 绑定的 client_id 列表(一对多)
Gateway::sendToUid($uid, $data); // 向所有 uid 发送
Gateway::joinGroup($client_id, $group);  // 把该 client_id 加入群组
Gateway::leaveGroup($client_id, $group); // 将 client_id 离开群组
Gateway::sendToGroup($group, $data);     // 向某群组 group 发送
Gateway::getClientCountByGroup($group);  // 获取某个组的在线连接数
Gateway::getClientSessionsByGroup($group); // 获取某个组的连接信息
Gateway::getClientInfoByGroup($group);   // getClientSessionsByGroup 的别名
Gateway::getAllClientCount();     // 获取所有的在线连接数
Gateway::getAllClientSessions();  // 获取所有在线用户的 session
Gateway::getAllClientInfo();      // getAllClientSessions 的别名
Gateway::setSession($client_id, $session);      // 设置 session,原 session 值会被覆盖
Gateway::updateSession($client_id, $session);   // 更新 session,实际上是与旧的session合并
Gateway::getSession($client_id);  // 获取某个 client_id的 session

 三. 实际IM应用

一般来说开发者只需要关注Applications/YourApp/Events.php。因为所有业务代码都在这里开始的。vendor目录为框架目录,开发者不要改动,也不用去理解。

其它start_gateway.php start_businessworker.php start_register.php分别是进程启动脚本,开发者一般不需要改动这三个文件。三个脚本统一由根目录的start.php启动。

Events.php
例如下面是一个聊天室示例

<?php
use \GatewayWorker\Lib\Gateway;
class Events
{
    /**
     * 当客户端连接时触发
     * 如果业务不需此回调可以删除onConnect
     * @param int $client_id 连接id
     */
    public static function onConnect($client_id)
    {
        // 向当前client_id发送数据
        Gateway::sendToClient($client_id, "Hello $client_id");
        // 向所有人发送
        Gateway::sendToAll("$client_id login");
    }

   /**
    * 当客户端发来消息时触发
    * @param int $client_id 连接id
    * @param string $message 具体消息
    */
   public static function onMessage($client_id, $message)
   {
        // 向所有人发送
        Gateway::sendToAll("$client_id said $message");
   }

   /**
    * 当用户断开连接时触发
    * @param int $client_id 连接id
    */
   public static function onClose($client_id)
   {
       // 向所有人发送
       GateWay::sendToAll("$client_id logout");
   }
}


Events.php中定义5个事件回调方法,

onWorkerStart businessWorker进程启动事件(一般用不到)
onConnect 连接事件(比较少用到)
onMessage 消息事件(必用)
onClose 连接断开事件(比较常用到)
onWorkerStop businessWorker进程退出事件(几乎用不到)
5个回调接口说明参见 Events类的回调接口 一节

其中消息事件onMessage是必须的,其它事件回调可以不实现。

<?php
use \GatewayWorker\Lib\Gateway;
class Events
{
   /**
    * 当客户端发来消息时触发
    * @param int $client_id 连接id
    * @param string $message 具体消息
    */
   public static function onMessage($client_id, $message)
   {
        // 向所有人发送
        Gateway::sendToAll("$client_id said $message");
   }
}


start_gateway.php
start_gateway.php为gateway进程启动脚本,主要定义了客户端连接的端口号、协议等信息,具体参见 Gateway类的使用一节。

客户端连接的就是start_gateway.php中初始化的Gateway端口。

start_businessworker.php
start_businessworker.php为businessWorker进程启动脚本,也即是调用Events.php的业务处理进程,具体参见 BusinessWorker类的使用一节。

start_register.php
start_register.php为注册服务启动脚本,用于协调GatewayWorker集群内部Gateway与Worker的通信,参见Register类使用一节。


http://www.kler.cn/a/294547.html

相关文章:

  • HelloMeme 上手即用教程
  • 前端常用布局模板39套,纯CSS实现布局
  • leetcode hot100【LeetCode 114.二叉树展开为链表】java实现
  • Java 网络编程(一)—— UDP数据报套接字编程
  • 使用@react-three/fiber,@mkkellogg/gaussian-splats-3d加载.splat,.ply,.ksplat文件
  • 小面馆叫号取餐流程 佳易王面馆米线店点餐叫号管理系统操作教程
  • [建模已更新]2024数学建模国赛高教社杯A题:“板凳龙” 闹元宵 思路代码文章助攻手把手保姆级
  • Hive整合MySQL
  • tabBar设置底部菜单选项以及iconfont图标
  • Java学习第七天
  • 【功能实现】如何实现点击后跳转到顶部??
  • 57-java csrf防御方案
  • 【Redis】Redis 集群搭建与管理: 原理、实现与操作
  • vue项目打包后,生成的index.html直接本地打开后没内容
  • Web:攻防世界unseping
  • 11Python的Pandas:可视化
  • Element Plus(Vue 3 版本)来实现图片轮播
  • P01-Java何谓数组
  • sheng的学习笔记-AI-概率图,隐马尔可夫HMM,马尔可夫随机场MRF,条件随机场CRF
  • 尝试用java spring boot+VUE3实现前后端分离部署(8/31)
  • 时间段切块算法
  • Flask中 blinker 是什么
  • 【Spring基础1】- Spring 启示录-理解IoC控制反转
  • 电脑删除的Word文件怎么恢复?快速恢复技巧分享
  • C++入门基础
  • Mail PHP: 如何设置SMTP服务器以发送邮件?