zoukankan      html  css  js  c++  java
  • 利用Swoole编写一个TCP服务器,顺带测试下Swoole的4层生命周期

    1首先我们写一个入口脚本,这里简单点的功能就是开启服务和关闭服务

    <?php
    //CLI命令
    if(isset($argv[1]) && in_array($argv[1], ['start', 'restart', 'status', 'stop', 'reload']))define('CLI_COMMAND', $argv[1]);
    else define('CLI_COMMAND', 'start');
    define('ROOT',__DIR__);
    define('TMP_PATH',ROOT.DIRECTORY_SEPARATOR.'tmp'.DIRECTORY_SEPARATOR);
    define('APP_NAME','mySwoole');
    require_once 'ServerCallFun.php';
    Class Root
    {
        static public $Ip  = '127.0.0.1';
        static public $port  = 9510;
        //swoole对象
        Static Public $serv = null;
    
        //进程对象
        Static Public $worker = null;
    
        /**
         * 主框架运行
         */
        Static Public function run()
        {
            $command = 'Root::' . CLI_COMMAND;
            $command();
        }
    
        /**
         * 启动框架
         */
        Static Private function start()
        {
            if(is_file(TMP_PATH . 'server.pid')){
                $pid = @file_get_contents(TMP_PATH . 'server.pid');
                if($pid && swoole_process::kill($pid, 0))die("Framework has been started!" . PHP_EOL);
            }
            echo "Framework Starting...", PHP_EOL;
            date_default_timezone_set('Asia/Shanghai');
            $setup = [
                'pid_file' => TMP_PATH.'server.pid',//在Server启动时自动将master进程的PID写入到文件,在Server关闭时自动删除PID文件
                'reactor_num' => 4,//reactor_num建议设置为CPU核数的1-4倍
                'worker_num' => 4,
                'backlog' => 128,//Listen队列长度,如backlog => 128,此参数将决定最多同时有多少个等待accept的连接。
                'max_request' => 100,//设置worker进程的最大任务数,默认为0,一个worker进程在处理完超过此数值的任务后将自动退出,进程退出后会释放所有内存和资源。
                'dispatch_mode' =>3,//抢占模式,主进程会根据Worker的忙闲状态选择投递,只会投递给处于闲置状态的Worker
                'daemonize'=>true,
                'log_file' => TMP_PATH .'swoole.log',//开启守护进程模式后(daemonize => true),标准输出将会被重定向到log_file。在PHP代码中echo/var_dump/print等打印到屏幕的内容会写入到log_file文件日志标号
    
            ];
            self::$serv = new swoole_server(self::$Ip,self::$port) or die('Swoole Starting Failed!' . PHP_EOL);
            self::$serv->set($setup);
            self::$serv->on('start', 'ServerCallFun::start');//在主进程start后调用
            self::$serv->on('managerstart', 'ServerCallFun::managerStart');//管理进程开启后
    
            //设置工作/任务进程启动回调
            self::$serv->on('workerstart', 'ServerCallFun::onWorkstart');
            /*self::$serv->on('request',function ($request, $response) {
                $response->header("Content-Type", "text/html; charset=utf-8");
                $response->end("<h1>Hello Swoole. #".rand(1000, 9999)."</h1>");
            });*/
            //监听连接进入事件
            self::$serv->on('connect',function ($serv, $fd) {
                echo "Client: Connect.
    ";
            });
    
            //监听数据接收事件
            self::$serv->on('receive','ServerCallFun::onReceive');
    
            //监听连接关闭事件
            self::$serv->on('close',function ($serv, $fd) {
                echo "Client: Close.
    ";
            });
    
            //在启动之前添加一个全局的内存tabel监控所有的进程状态
    
    
            //实例启动前执行(start前的状态全部是程序全局期)
            self::$serv->start();
        }
    
        Static Private function stop(){
            $pid = @file_get_contents(TMP_PATH . 'server.pid');
            if($pid){
                if(swoole_process::kill($pid, 0))swoole_process::kill($pid, 15);
                else{
                    foreach(glob(TMP_PATH . '*.pid') as $filename){
                        $pid = @file_get_contents($filename);
                        if(swoole_process::kill($pid, 0))swoole_process::kill($pid, 9);
                        @unlink($filename);
                    }
                }
                die('Stop of Framework Success!' . PHP_EOL);
            }
            die('Framework not started!' . PHP_EOL);
        }
    
    }
    Root::run();

    进一步来了解下这里是主要用来干嘛的

    首先是声明了当前的执行文件的绝对路径,这里pid_file一定是要绝对路径

    这里运行start命令会调用start的方法,这里主要是设置配置参数然后开启swoole默认的tcp服务。swoole的回调函数我放到另外一个类中处理了,这里是为了理解swoole的生命周期有意为之。

    设置的默认参数中比较重要的是pid_file这个参数,这个可以用来重启和关闭服务进程。

    在start方法执行前,所有的require和变量都是在第一层swoole生命周期中为程序全局期。

    回调函数类是

    <?php
    require_once 'CmdController.php';
    class ServerCallFun{
        static function start(swoole_server $server){
            swoole_set_process_name("Master process");
            //绑定状态事件
            //swoole_process::signal(SIGUSR1, 'RootHttp::status');
            //绑定重载事件
            swoole_process::signal(SIGUSR2, function() use ($server){
                $server->reload();
            });
        }
    
        static function managerStart(swoole_server $server){
            $num = count(glob(TMP_PATH . 'manager_*.pid'));
            file_put_contents(TMP_PATH . 'manager_'. $num .'.pid', $server->manager_pid);
            swoole_set_process_name("Manager[{$num}] process");
        }
    
        static Public function onWorkstart(swoole_server $server, int $worker_id)
        {
            //实例化进程对象
            Root::$worker = new self();
            if($server->taskworker) {
                file_put_contents(TMP_PATH . "task_{$worker_id}.pid", $server->worker_pid);
                swoole_set_process_name("Tasker[{$worker_id}] process ");
                echo "TaskID[{$worker_id}] PID[". $server->worker_pid ."] creation finish!" . PHP_EOL;
            } else {
                file_put_contents(TMP_PATH . "worker_{$worker_id}.pid", $server->worker_pid);
                swoole_set_process_name("Worker[{$worker_id}] process");
                echo "WorkerID[{$worker_id}] PID[". $server->worker_pid ."] creation finish!" . PHP_EOL;
            }
        }
    
        static Public function onConnect($serv, $fd)
        {
            
        }
    
        static Public function onReceive($serv, $fd, $from_id, $data)
        {
            $msg = CmdController::run($data,$fd,$from_id);
            $serv->send($fd,json_encode($msg));
        }
    
        static Public function onClose($serv, $fd)
        {
            
        }
    }

    这里我们在主进程开启后执行了start的回调,添加上了重启热更新子进程的信号siguser2.进行server reload.并且将进程名字设置为Master Process

    对管理进程也设置了回调。也是为了更名

    对work进程设置回调更名,同时因为是守护方式运行服务,php的输出会输出到log_file配置的路径中

    然后我在测试receive中测试下进程全局期中会出现什么情况

    <?php
    class CmdController{
        static public $count = 0;
        static public function run($recive,$fd,$fromId){
            self::$count++;
            $returnArr = ['ret'=>-1,'data'=>'','msg'=>''];
            if($recive){
                $returnArr['ret']  = 0;
                $returnArr['data'] = self::$count.";{$fd}-{$fromId}:getRequest[{$recive}]->getReponse[Success]";
            }
            return $returnArr;
        }
    }

    如果是我们的理解,我们会认为每次tcp客户端发送数据,然后服务端接收到的话,就是让count+1。其实这里就是进程的全局期,4个work会独立保存各自的数据。所以会出现下面,count出现4次重复然后自增的情况。

    如何开启测试的服务器 php index.php start

    如何关闭测试的服务器 php index.php stop

  • 相关阅读:
    py爬取英文文档学习单词
    windows 下使clion支持c++11操作记录
    angular在ie8下的一个bug
    连连看小游戏前端实现
    如何禁止页面文字被选中
    分享一个BUG
    描点链接元素的优化提升用户体验
    模拟淘宝滚动显示问题解决入口
    简易图片轮播效果
    支付战争
  • 原文地址:https://www.cnblogs.com/gavinjunftd/p/9145379.html
Copyright © 2011-2022 走看看