手记

SWOOLE 从入门到放弃之写个小框架(十三)

首先,改造Router.php
SWOOLE 从入门到放弃之写个小框架(八) 中,已经写好了处理HTTP请求路由的方法,接下来就开始写处理WEBSOCKET请求路由的方法。
开始写WEBSOCKET请求路由前,我需要确定一个数据交互的数据格式,比如,客户端发起请求后,我们要根据请求的内容来路由到指定的module->controller->action上,并且在需要时还要带上相应的参数,首选就是JSON,原因就是JSON格式清晰简单,兼容性也比较好。我们先设定一个最基本的拉取用户信息的格式

{
    "cmd":"user/info/get",    //请求地址,对应module->controller->action
    "uid": 1      // 参数
}

有了这个大前提,Router.php就很容易改造了。拿到websocket的数据帧后,直接把json格式解析成数组格式,然后还希望它能像http路由那样URL重写缩短URL地址。代码如下

/**
     * WebSocket 路由解析
     */
    public function websocket($data) {

        $data = json_decode ($data , true );
        if(empty($data)){
            echo 'WEBSOCKET-json解包错误',PHP_EOL;
            return ['m'=>NULL ,'c'=>NULL,'a'=>NULL ,'p' =>  NULL] ;
        }

        $path = empty($data['cmd']) ? '' : trim($data['cmd'], '/');

        if(empty($path)){
            echo '请求地址错误',PHP_EOL;
            return ['m'=>NULL ,'c'=>NULL,'a'=>NULL ,'p' =>  NULL] ;
        }

        if (!empty(self::$config['rules']) && isset(self::$config['rules'][$path])) {
            $path =  self::$config['rules'][$path];
        }

        $param = explode( "/" , $path);

        $module     =   array_shift ($param);
        $controller =   array_shift ($param);
        $action     =   array_shift ($param);
        unset($data['cmd']);
        return ['m'=>$module ,'c'=>$controller,'a'=>$action ,'p' =>  $data] ;
    }

Router.php改造完成,代码请移步 https://gitee.com/pizzzz/piz/blob/master/frame/Lib/Router.php

接下来改造App.php。
使用同样的方式,把http和websocket的处理方式分开,在App.php新增websocket方法。为了能让项目中的控制器可以直接向客户端推送内容,我们需要在它初始化时把server对象传递给控制器,同时还要把fd也传过去,代码如下

public function websocket($server,$frame)
    {
        $router = $router = Router::get_instance ()->websocket( $frame ->data );

        $app_namespace  = Config::get_instance ()->get('app.namespace');
        $module         = $router['m'] ;
        $controller     = $router['c'] ;
        $action         = $router['a'] ;
        $param          = $router['p'] ;

        $classname = "\\{$app_namespace}\\modules\\{$module}\\{$controller}";

        if ( ! isset( self ::$map[ $classname ] ) ) {
            try{
                $class = new $classname;
                self ::$map[ $classname ] = $class;
            }catch (\Exception $e){
                echo $e->getMessage (),PHP_EOL;
                return ;
            }
        }
        try{
            self::$map[$classname]->server = $server;
            self::$map[$classname]->fd = $frame->fd;
            self::$map[$classname]->param = $param;
            self::$map[$classname]->$action();
        }catch(\Exception $e){
            echo $e->getMessage (),PHP_EOL;
            return ;
        }
    }

创建控制器文件 app/modules/user/info.php,代码如下

<?php
namespace app\modules\user;
class info
{
    public function get(){
        $content = "Uid:{$this->param['uid']};Name:test;say:{$this->param['msg']}";
        $this->server->push($this->fd,$content);
    }
}

启动start.php,访问http://192.168.1.111:9501/ws.html

运行效果如下

代码已上传至码云 https://gitee.com/pizzzz/piz

下一篇 , 用TASK来实现WEBSOCKET的批量回复

1人推荐
随时随地看视频
慕课网APP