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.\n"; }); //監聽數據接收事件 self::$serv->on('receive','ServerCallFun::onReceive'); //監聽連接關閉事件 self::$serv->on('close',function ($serv, $fd) { echo "Client: Close.\n"; }); //在啟動之前添加一個全局的內存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, '\Root\Http::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