• workerman + gateway +thinkphp 简单使用


    1.Workerman是什么?(套用官网)

    Workerman是一款纯PHP开发的开源高性能的PHP socket 服务框架。

    Workerman不是重复造轮子,它不是一个MVC框架,而是一个更底层更通用的socket服务框架,你可以用它开发tcp代理、梯子代理、做游戏服务器、邮件服务器、ftp服务器、甚至开发一个php版本的redis、php版本的数据库、php版本的nginx、php版本的php-fpm等等。Workerman可以说是PHP领域的一次创新,让开发者彻底摆脱了PHP只能做WEB的束缚。

    实际上Workerman类似一个PHP版本的nginx,核心也是多进程+Epoll+非阻塞IO。Workerman每个进程能维持上万并发连接。由于本身常住内存,不依赖Apache、nginx、php-fpm这些容器,拥有超高的性能。同时支持TCP、UDP、UNIXSOCKET,支持长连接,支持Websocket、HTTP、WSS、HTTPS等通讯协以及各种自定义协议。拥有定时器、异步socket客户端、异步Mysql、异步Redis、异步Http、异步消息队列等众多高性能组件。

     2. GatewayWorker是什么?(套用官网)

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

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

    3. Gatewayworker + thinkphp

    数据交互模型:

    流程:

    1. 客户端(浏览器)发出socket请求与getwayworker建立连接
    2. 客户端发出http请求(注意是发送http请求处理业务,所有业务都放在tp处理)
    3. tp处理业务逻辑(把client_id与uid绑定、客户端分组、数据库查询等),然后调用gateway的接口把结果数据进行广播
    4. 客户端接收广播的数据,进行视图渲染

    4. 环境搭建

      1. workerman 与 gateway安装

    composer require workerman/workerman
    composer require workerman/gateway-worker

      官网实例 点击下载 

      2. 配置

      start_gateway.php文件配置(开启gateway服务,并在注册服务注册)

    <?php 
    
    use WorkermanWorker;
    use WorkermanWebServer;
    use GatewayWorkerGateway;
    use GatewayWorkerBusinessWorker;
    use WorkermanAutoloader;
    // 
    $context = array(
        'ssl' => array(
            'local_cert'  => '/etc/pki/tls/certs/public.pem', // 或者crt文件
            'local_pk'    => '/etc/pki/tls/private/214498534070135.key',
            'verify_peer' => false
        )
    );
    // gateway 进程,这里使用websocket协议,这里使用了443端口,所有要加载ssl的配置,websocket://0.0.0.0:443:允许所有任何客户端使用wss协议访问
    $gateway = new Gateway("websocket://0.0.0.0:443",$context);
    
    $gateway->transport = 'ssl';
    // gateway名称,status方便查看
    $gateway->name = 'YourAppGateway';
    // gateway进程数
    $gateway->count = 4;
    // 本机ip,分布式部署时使用内网ip
    $gateway->lanIp = '172.31.240.231';
    // 内部通讯起始端口,假如$gateway->count=4,起始端口为4000
    // 则一般会使用4000 4001 4002 4003 4个端口作为内部通讯端口 
    $gateway->startPort = 2900;
    // 服务注册地址
    $gateway->registerAddress = '172.31.240.231:1238';
    
    // 心跳检测  15秒一次
    $gateway->pingInterval = 15;
    
    $gateway->pingNotResponseLimit = 1;
    // 当pingData为空,服务器将不会向客户端发送心跳检测(为了节省服务器资源,心跳检测最好由客户端发起)
    $gateway->pingData = '';
     if(!defined('GLOBAL_START')) {
       Worker::runAll();
     }

      3. start_businessworker.php(开启businessworker服务,并在注册服务注册)

    <?php 
    use WorkermanWorker;
    use WorkermanWebServer;
    use GatewayWorkerGateway;
    use GatewayWorkerBusinessWorker;
    use WorkermanAutoloader;
    
    // bussinessWorker 进程
    $worker = new BusinessWorker();
    // worker名称
    $worker->name = 'YourAppBusinessWorker';
    // bussinessWorker进程数量
    $worker->count = 4;
    // 服务注册地址
    $worker->registerAddress = '172.40.239.231:1238';
    
    // 如果不是在根目录启动,则运行runAll方法
    if(!defined('GLOBAL_START')) {
        Worker::runAll();
    }

      4. start_register.php(开启注册服务)

    <?php 
    use WorkermanWorker;
    use GatewayWorkerRegister;
    
    // register 服务必须是text协议
    $register = new Register('text://172.40.239.231:1238');
    
    // 如果不是在根目录启动,则运行runAll方法
    if(!defined('GLOBAL_START')) {
        Worker::runAll();
    }

       5.  启动服务

        启动

        以debug(调试)方式启动

          php start.php start

        以daemon(守护进程)方式启动

          php start.php start -d

        停止

          php start.php stop

        重启

          php start.php restart

        平滑重启

          php start.php reload

        查看状态

          php start.php status

    5. 客户端操作(这是我基于小程序接口,封装的一个socket库)

        var socket = new Socket('wss://wss.xinyuruiyang.com');
        socket.on("open",function (res) {
          console.log('WebSocket连接已打开!')
          _this.setData({
            isOpenSocket: true
          });
        });
      // 初始化链接
      socket.on("init", function (data) {
        _this.setData({
          client_id: data.client_id
        });
        request({
          url: app.requestUrl('Admin/Match/bind'),
          data: {
            client_id: data.client_id,
            room: 1, // 分组1
          },
          success: res => {
            console.log(res, '用户绑定成功!');
          }
        })
      })
     

    6. gateway端操作

    <?php
    use GatewayWorkerLibGateway;
    use WorkermanLibTimer;
    class Events
    {
        public static $worker_id = null;
        /**
         * 当客户端连接时触发
         * 如果业务不需此回调可以删除onConnect
         * 
         * @param int $client_id 连接id
         */
        public static function onConnect($client_id) {
            // 向当前client_id发送数据(触发客户端的init时间)
            Gateway::sendToClient($client_id, json_encode(["init",["client_id"=>$client_id]]));
        }
    }

    7. tp端操作  

      Gateway::$registerAddress = '172.31.239.230:1238';
      class MatchController extends AdminController {
    private function bind_user($room,$client_id,$uid=''){
            if( empty($uid) ){
                $sk = $this->checksession();
                $openid = $this->get_openid($sk);
                $uid = D('User')->where(['openid'=>$openid])->getField('id');
            }
    
            // client_id与uid绑定
            Gateway::bindUid($client_id, $uid);
            // 加入某个群组(可调用多次加入多个群组)
            Gateway::joinGroup($client_id, $room);
         // 设置session Gateway
    ::setSession($client_id, ['uid'=>$uid]);
         // 获取客户端分组人数
    $number = Gateway::getClientCountByGroup($room); D('Match')->where(['rid'=>$room,'uid'=>$uid,'status'=>['in',['1','2']]])->save(['client_id'=>$client_id]); $message = D('Match')->where(['rid'=>$room,'status'=>['in',['1','2']]])->select(); foreach($message as &$v){ $v['user'] = D('User')->where(['id'=>$v['uid']])->find(); $v['user']['teamside'] = D('Match')->where(['rid'=>$room,'uid'=>$v['uid'],'status'=>['in',['1','2']]])->getField('teamside'); }
         // 向某个房间广播数据 Gateway
    ::sendToGroup($room, json_encode(["room",$message])); }
     }
  • 相关阅读:
    Check the string
    最简单的
    第七届ACM程序设计竞赛 (SDIBT)
    Cutie Pie
    CSS3 :nth-of-type() 与 nth-child()选择器
    Ajax 完整教程 转载地址:http://www.cnblogs.com/Garden-blog/archive/2011/03/11/1981778.html(转)
    排序:二元选择排序
    排序:堆排序
    排序:直接插入排序 稳定 n*n
    排序:冒泡和改进
  • 原文地址:https://www.cnblogs.com/dudeyouth/p/9017394.html
Copyright © 2020-2023  润新知