swoole结合支持thinkphp 5.0版本

安装swoole

pecl install swoole
修改PHP配置文件php.ini加入
extension=swoole.so

有可能不需要人工去加,安装时自动加入进来了,

查看swoole扩展是否安装好

/usr/local/php/bin/php -m

配制列表里面如果有swoole的话,恭喜你安装并配置swoole成功。

在index.php同级目录下面新新建ws.php文件,文件内容以下

<?php
class Ws {
    CONST HOST = "0.0.0.0";
    CONST PORT = 9501;

    public $ws = null;
    public function __construct() {
        $this->ws = new swoole_websocket_server(self::HOST, self::PORT);

        $this->ws->set(
            [
                'worker_num' => 4,//打开的进程数
                'daemonize'=>0,//1守护进程,在后台一直运行
            ]
        );

        //websocket继承于http_service,所以拥有http_service服务器的所有函数
        
        //http_service函数,
        $this->ws->on("start", [$this, 'onStart']);      
        $this->ws->on("workerstart", [$this, 'onWorkerStart']);//此事件在Worker进程/Task进程启动时发生。
        $this->ws->on("request", [$this, 'onRequest']);
        $this->ws->on("task", [$this, 'onTask']);
        $this->ws->on("finish", [$this, 'onFinish']);
        
        //websocket函数
        $this->ws->on("open", [$this, 'onOpen']);
        $this->ws->on("message", [$this, 'onMessage']);
        $this->ws->on("close", [$this, 'onClose']);
        $this->ws->start();//开启
    }

    /**
     * @param $server
     */
    public function onStart($server) {
        swoole_set_process_name("websocket");//修改进程名称,非必要
    }
    /**
     * @param $server
     * @param $worker_id
     */
    public function onWorkerStart($server,  $worker_id) {
        
        //swoole是cli运行,执行地址path会无法正确找到,所以把base.php里面定义的常量提出来,设置为假,
        //注意:记住把源代码base.php里面的define('IS_CLI',false)代码去掉(常量不能重复定义),在index.php里面加入代码:define('IS_CLI', PHP_SAPI == 'cli' ? true : false);
        define('IS_CLI',false);//        
        
        //当进程运行时,把框架代码加载进来
        // 定义应用目录
        define('APP_PATH', __DIR__ . '/../application/');
        // 加载框架里面的文件
        require __DIR__ . '/../thinkphp/base.php';
    }

    /**
     * request回调
     * 当请求过来时,会调用此方法,调用thinkphp真正的执行逻辑
     * @param $request
     * @param $response
     */
    public function onRequest($request, $response) {
        //因为这些全局变量会在进程的内存里面不变,所有每次请求到来先清空值。
        
        if($request->server['request_uri'] == '/favicon.ico') {
            $response->status(404);
            $response->end();
            return ;
        }
        $_SERVER  =  [];
        if(isset($request->server)) {
            foreach($request->server as $k => $v) {
                $_SERVER[strtoupper($k)] = $v;
            }
        }
        if(isset($request->header)) {
            foreach($request->header as $k => $v) {
                $_SERVER[strtoupper($k)] = $v;
            }
        }

        $_GET = [];
        if(isset($request->get)) {
            foreach($request->get as $k => $v) {
                $_GET[$k] = $v;
            }
        }
        $_FILES = [];
        if(isset($request->files)) {
            foreach($request->files as $k => $v) {
                $_FILES[$k] = $v;
            }
        }
        $_POST = [];
        if(isset($request->post)) {
            foreach($request->post as $k => $v) {
                $_POST[$k] = $v;
            }
        }

        $_POST['http_server'] = $this->ws;//把对像传过去

        ob_start();
        try {
            
            // 执行应用并响应
            think\App::run()->send();
        }catch (\Exception $e) {
            // todo
            echo $e->getMessage();
        }

        $res = ob_get_contents();
        ob_end_clean();
        $response->end($res);
    }



    /**
     * 监听ws连接事件
     * @param $ws
     * @param $request
     */
    public function onOpen($ws, $request) {
        $ws->push($request->fd, "hello, welcome\n");//发送消息给客户端
        
        /*
        与thinkphp框架结合
        think\App::run();//如果不执行这行代码,框架里面很多功能用不了
        
        //执类指定类里面的指定方法
        $obj=new \app\index\controller\Login();
        $obj->action();
        */
        
    }

    /**
     * 接收客户端传过来的消息事件
     * @param $ws
     * @param $frame
     */
    public function onMessage($ws, $frame) { 
        $msg=$frame->data;//接收客户端传过来的消息
        $ws->push($frame->fd, "server-push:".date("Y-m-d H:i:s"));
    }

    /**
     * ws客户端关闭时调用事件
     * @param $ws
     * @param $fd
     */
    public function onClose($ws, $fd) {
        echo "clientid:{$fd}\n";
    }

    
    
        /**
     * @param $serv
     * @param $taskId
     * @param $workerId
     * @param $data
     */
    public function onTask($serv, $taskId, $workerId, $data) {

        // 分发 task 任务机制,让不同的任务 走不同的逻辑
        $obj = new app\common\lib\task\Task;

        $method = $data['method'];
        $flag = $obj->$method($data['data'], $serv);
        /*$obj = new app\common\lib\ali\Sms();
        try {
            $response = $obj::sendSms($data['phone'], $data['code']);
        }catch (\Exception $e) {
            // todo
            echo $e->getMessage();
        }*/

        return $flag; // 告诉worker
    }

    /**
     * @param $serv
     * @param $taskId
     * @param $data
     */
    public function onFinish($serv, $taskId, $data) {
        echo "taskId:{$taskId}\n";
        echo "finish-data-sucess:{$data}\n";
    }

}

new Ws();
因为tp里面的全局变量会在进程的内存里面不变,会导致执行地址path不更新,需要修改源代码
修改框架源代码thinkphp/library/think/Request.php,两处地方,如下2图:

上面是服务端websocket代码,下面是客户端JS
<script>
var wsServer = 'ws://193.112.27.236:9501/index/login/a?cc=1'; //websocket服务端地址,记住ws://不能去掉
var websocket = new WebSocket(wsServer);
websocket.onopen = function (evt) {
    console.log("Connected to WebSocket server.");
	websocket.send(1111);//发送数据给服务器
};

//服务端关闭时调用
websocket.onclose = function (evt) {
    console.log("Disconnected");
};

//服务端向客户端发送消息时调用
websocket.onmessage = function (evt) {
    console.log('Retrieved data from server: ' + evt.data);
};

//服务端报错时调用
websocket.onerror = function (evt, e) {
    console.log('Error occured: ' + evt.data);
};
</script>

  注意:linux上面运行开启服务时

php ws.php

以上命令可能会有问题,因为cli模式下运行的php 可能跟你项目运行的php版本跟配置文件不一样

可以使用以下命令来保证准确:

 查看是否启动成功

 

修改代码之后,需要杀死进程,重新启动

猜你喜欢

转载自www.cnblogs.com/liming-php/p/10522788.html