swoole+mysql连接池+redis (可以处理多个房间,一个房间多个定时任务,决定于业务逻辑)

时间:2021-10-21 01:44:42

代码库  https://gitee.com/chenx885/swoole.git

具体的业务逻辑,要自己去实现(这里的swoole版本是用的1.9.8 不是很高,没有用到携程)

swoole 核心代码

<?php
require_once 'redis.php';
require_once 'Mysql.php';
class Server {
    private $serv;
    private $connection_num = 20;//连接数量
    private $connection_obj = [];  //mysql对象
    private $avil_connection_num = 20;//可用连接
    //构造redis
    public function InstRedis(){
        $redis = new RedisCus();
        $redis->connect(array('host' => '127.0.0.1', 'port' => 6379, 'pwd' =>""));
        $redis->select_db(8);
        return $redis;
    }
    //构造MySQL
    public function InstMysql(){
        $configArr=array("host"=>"127.0.0.1","port"=>"3306","user"=>"leadcommon","passwd"=>"YncvnTGEmq","dbname"=>"waiqu");
        return new MMysql($configArr);
    }
    public function __construct() {
        $this->serv = new swoole_server ( "0.0.0.0", 9501 );        
        $this->serv->set ( array (
                'worker_num' => 2,
                'daemonize' => false,
                'max_request' => 10000,
                'dispatch_mode' => 2,
                'debug_mode' => 1,
                'task_worker_num'=>200,
                'log_file'=>'./err.log'
        ) );
        //创建链接池
        if($this->connection_num>0){
            for($i=0;$i<$this->connection_num;$i++){
                $this->connection_obj[] = $this->InstMysql();
            }
        }
        $this->serv->on ( 'Start', array ($this,'onStart'));
        //开始一个进程【多个实例化redis和mysql】
        $this->serv->on('WorkerStart', function (swoole_server $serv,$worker_id){
            //创建redis
             $serv->redis=$this->InstRedis();
            //$serv->mysql=$this->InstMysql();
        
        });
        $this->serv->on ( 'Connect', array ($this,'onConnect'));
        $this->serv->on ( 'Receive', array ($this,'onReceive'));
        $this->serv->on('Task',array($this,'onTask'));
        $this->serv->on('Finish',array($this,'onFinish'));
        $this->serv->on ( 'Close', array ($this,'onClose' ));
        $this->serv->start ();
    }
    public function onStart($serv) {
        echo " on Start\n";
    }

    public function onConnect($serv, $fd, $from_id) {
        $serv->send ($fd,"connect success, hi {$fd}!" );
    }
    //接收参数,逻辑处理
    public function onReceive(swoole_server $serv, $fd, $from_id, $data) {
        $request = json_decode(trim($data), true);
        if (!is_array($request)) {
            $json=json_encode(array('type'=>'-1','msg'=>'参数错误'));
            return $serv->send($fd,$json);
        }
        //判断token是否错误
        $request['fd']=$fd;
        $task_id = $serv->task($request);
        $serv->send($fd, "分发任务,任务id为$task_id\n");
        
    }
    //任务
    public function onTask(swoole_server $serv, $task_id, $from_id,$data){
        $cmd=$data['cmd'];
        $fd=$data['fd'];
        switch ($cmd) {
            case 1://进入房间
                $this->entryRoom($serv,$fd,$from_id,$data);
                break;
            case 2: //开始游戏
                $this->beginPlay($serv,$fd,$from_id,$data);
                break;
            case 3: //退出房间
                $this->breakRoom($serv,$fd,$from_id,$data);
                break;
            default:
                $serv->send ($fd,"cmd参数错误" );
                break;
        }
        $timer=swoole_timer_tick(20000, function() use ($serv,$task_id, $data){
                echo " 任务=$task_id ||20秒触发 timeout\n".json_encode($data)."\n";
        });
        swoole_timer_after(50000, function() use($serv,$task_id,$timer) {
            echo '50秒清除';
            swoole_timer_clear($timer);
        });
        //不能清除其他进程的定时器,只用于当前进程
        //    swoole_timer_clear($timer);
        echo "Tasker进程接收到数据".$timer."|";
        echo "#{$serv->worker_id}\tonTask: [PID={$serv->worker_pid}]: task_id=$task_id, data_len=".count($data).".".PHP_EOL;
        $serv->finish($data);
    }
    //任务完成触发
    public function onFinish(swoole_server $serv, $task_id, $data){
        echo "Task#$task_id finished, data_len=".count($data).PHP_EOL;
    }
    //关闭
    public function onClose($serv, $fd, $from_id) {
        echo "Client {$fd} close connection\n";
    }
    
    //进入房间
    public function entryRoom($serv,$fd,$from_id,$data){
        $pdo=$this->beginConn();
        if(!empty($data['room_id'])){
            $room_id =$data['room_id'];
        }
        $user_token =$pdo->field('user_id,nickname')->where(array('user_id' =>547723))->select('hl_user');
        $user_token['avil_connection_num']=$this->avil_connection_num;
        $this->closeConn($pdo);
        $this->sendMsg($serv,$fd,$user_token);
    }
    //准备开始时间
    public function beginPlay($serv,$fd,$from_id,$data){
        
    }
    //发送消息
    public function sendMsg($serv,$fd,$message){
        $msg=json_encode($message);
        $serv->send($fd,$msg);
    }
    //开始使用链接池
    public function beginConn(){
        //链接数
        $pdo = array_pop($this->connection_obj);
        //数量大于小于1 链接不能ping上,重新实例mysql
        if($this->avil_connection_num<1 || ($pdo->pdo_ping($pdo) != true)){
            $pdo= $this->InstMysql();
        }
        //可用连接数减1
        $this->avil_connection_num --;
        return $pdo;
    }
    //关闭链接池
    public function closeConn($pdo){
        array_push($this->connection_obj,$pdo);
        $this->avil_connection_num ++;
    }
}
// 启动服务器
$server = new Server (); 

 

 

这里多个房间,一个房间有多个定时任务,要根据业务代码,自己来加

swoole_timer_after(),这个定时器很重要,根据业务逻辑比方type=1 触发一个定时任务,type=2触发一个定时任务。就可以实现了。

这个具体的稳定性和并发。还要去探究一下。