tp5配合Workerman实现一些消息推送,wss微信小程序能用
编辑时间:2021-03-28 作者:金满斗 浏览量:4600 来源:原创

aardio里开发websocket服务端和客户端很简单,前几天搞过一个聊天室玩玩。

php里也想搞个websocket服务器,因为php和linux更配。但有时候又想用windows服务器,Workerman就成了不二选择。

TP5里也介绍了Workerman的库,具体看文档 https://www.kancloud.cn/manual/thinkphp5_1/354134


启动到tp环境后php命令行启动 php think worker:server  ,linux也支持支持reload|restart|stop|status 操作   如php think worker:server reload。

默认在配置文件里有个worker_server.php配置文件。但把事件处理什么的都写在配置文件里好像不是我的风格。


<?php
use think\facade\Env;

// +----------------------------------------------------------------------
// | Workerman设置 仅对 php think worker:server 指令有效
// +----------------------------------------------------------------------
return [
    // 扩展自身需要的配置
    'protocol'       => 'websocket'// 协议 支持 tcp udp unix http websocket text
    'host'           => '0.0.0.0'// 监听地址
    'port'           => 8876// 监听端口
    'socket'         => ''// 完整监听地址
    'context'        => [], // socket 上下文选项
    'worker_class'   => ''// 自定义Workerman服务类名 支持数组定义多个服务

    // 支持workerman的所有配置参数
    'name'           => 'thinkphp',
    'count'          => 4,
    'daemonize'      => false,
    'pidFile'        => Env::get('runtime_path') . 'worker.pid',

    // 支持事件回调
    // onWorkerStart
    'onWorkerStart'  => function ($worker) {

    },
    // onWorkerReload
    'onWorkerReload' => function ($worker) {

    },
    // onConnect
    'onConnect'      => function ($connection) {

    },
    // onMessage
    'onMessage'      => function ($connection$data) {
        $connection->send('你好,啊购');
    },
    // onClose
    'onClose'        => function ($connection) {

    },
    // onError
    'onError'        => function ($connection$code$msg) {
        echo "error [ $code ] $msg\n";
    },
];

按说明单独配置个库吧,不过配置库后好像很多配置文件都就失效了



'worker_class'   => 'app\stock\Worker'// 自定义Workerman服务类名 支持数组定义多个服务

另一份文档 http://doc.workerman.net/worker/on-connect.html

TP的文档里有用单独服务类的例子,可惜不完全,自己试了下,和以前写的那个aardio网络聊天的进行通讯,可以。那就上上来吧。反正自己的业务逻辑不是这个。



<?php
/**
 *
 * @author 劲松_楚鸟
 * @date 2021-03-28 14:18:00
 * @workes websocket服务器组件,用来试试和以前aardio写的聊天页面连
 */

namespace app\stock;
use think\worker\Server;
use think\facade\App;
class Worker extends Server
{
    protected $socket = 'websocket://0.0.0.0:8876';
    // 扩展自身需要的配置
    protected $option =[
        // 支持workerman的所有配置参数
        'name'           => '聊天测试',     //进程名称,方便识别
        'count'          => 4
    ];

     /**
     * 看文本调试信息
     * $data-变量
     * PHP_EOL-根据系统环境确定换行(换行)
     * FILE_APPEND - 追加参数
    **/
    private  function log($data){
        $log_filename = App::getRuntimePath() . 'log'. DIRECTORY_SEPARATOR  . date('Ym') . DIRECTORY_SEPARATOR .date('d'). ".log";
        if(is_array($data)){
            $text='[result]='.var_export($data,true).';';
        }else{
            $text = $data;
        }
        $contents = '['.date('Y-m-d H:i:s',time()).']'.PHP_EOL.$text;
        $res = file_put_contents($log_filename,$contents.PHP_EOL, FILE_APPEND);

    }

    //初始群发信息
    protected function initcopy(){
        $tab = $this->globalEvent;
        //第一次,全转发
        foreach($tab  as  $k=>$v)
        {
            $this->worker->connections[$k]->send(\json_encode($v));
        }
    }


    //客户端连接过来初始事件,数据存全局
    protected function onopeninit($connection){
        $newtab = [];
        $newtab['ip'] = $connection->getRemoteIp(); 
        $newtab['trme'] = \date("Y-m-d H:m:s",time());   //登录时间
        $clent = $connection->id;      //连接进程标志
        $this->globalEvent[$clent] = $newtab ;     //用来存储所有标志,嘻哈表,取快
    }

    //客户端连接过来初始事件,没有的就从表里删除
    protected function rm_hsocket($id){
        unset($this->globalEvent[$id]);
        
    }

    //启动回调函数
    public function onWorkerStart($worker)
    {
        echo '启动啦';
    }

    
    //客户端与Workerman建立连接时(TCP三次握手完成后)触发的回调函数
    public function onConnect($connection)
    {
        $this->onopeninit($connection);
    }


    //当客户端通过连接发来数据时(Workerman收到数据时)触发的回调函数
    public function onMessage($connection,$data)
    {
        try {
            $data = json_decode($data,true);
        } catch (\Throwable $th) {
            $this->log($th) ;
        }
        $this->log($data) ;
        if($data){
            if(isset($data['status'])){
                switch ($data['status']) {  //这里通过status判断不同的状态进行不同的事件
                    case 'init':     //初始,第一次发信息
                        if(!isset($data['name'])) return  $this->rm_hsocket($connection->id) ;  //全局移除那个指针
                        $tab = $this->globalEvent;  //全局静态
                        $this->log($tab) ;
                        $tab[$connection->id]['name']=$data['name'];   //标志
                        $this->initcopy($tab);   //第一次连接后发送初始化界面信息
                        break;
                    
                    default:
                        # code...
                        break;
                }
            }
        }

    }

    

    //设置Worker收到reload信号后执行的回调。用的少
    public function onWorkerReload($worker)
    {
        
    }

    //当客户端连接与Workerman断开时触发的回调函数
    public function onClose($connection)
    {   
        return  $this->rm_hsocket($connection->id) ;  //全局移除那个指针  
    }

    //报错时回调函数
    public function onError($connection$code$msg)
    {
        echo "error [ $code ] $msg\n";
    }



}

没写详细和完全,主要是测试的,我的业务逻辑不搞这。

以前aardio写的聊天测试,可以和这个配合看:http://blog.jvbaopeng.com/blog/156.html


最后噗嗤噗嗤写完了,然后小程序上好像不能用,一链接就断,wss的

加上这个配置就好

// 扩展自身需要的配置
    protected $option =[
        // 支持workerman的所有配置参数
        'name'           => '聚宝盆记账易',     //进程名称,方便识别
        'count'          => 4,
        'transport'      => 'ssl'
    ];
    
    // 证书最好是申请的证书
   protected  $context = array(
        // 更多ssl选项请参考手册 http://php.net/manual/zh/context.ssl.php
        'ssl' => array(
            // 请使用绝对路径
            'local_cert'                 => './zhen/my.pem'// 也可以是crt文件
            'local_pk'                   => './zhen/my.key',
            'verify_peer'                => false,
        )
    );


来说两句吧