// 解析命令.
protected static function parseCommand()
{
global $argv;
// Check argv;
$start_file = $argv[0];
$available_commands = array(
'start', // 启动.
'stop', // 停止.
'restart', // 重启:先stop->后start.
'reload', // 重新加载配置(相当于子进程慢慢重启,保证客户端链接不挂)
'status', // 查看当前服务运行状态.
'connections', // 查看客户端连接情况.
);
// 必须要输入命令:php start.php start|restart|stop...
$usage = "Usage: php yourfile.php {" . implode('|', $available_commands) . "} [-d]\n";
if (!isset($argv[1]) || !in_array($argv[1], $available_commands)) {
exit($usage);
}
// 获取命令.
$command = trim($argv[1]);
// 参数:-d守护进程,-g平滑的停止worker.
$command2 = isset($argv[2]) ? $argv[2] : '';
// Start command.
$mode = '';
if ($command === 'start') {
// 守护进程模式.
if ($command2 === '-d' || Worker::$daemonize) {
$mode = 'in DAEMON mode';
} else {
// 调试模式.
$mode = 'in DEBUG mode';
}
}
self::log("Workerman[$start_file] $command $mode");
// 获取workerman服务的主进程id.
$master_pid = is_file(self::$pidFile) ? file_get_contents(self::$pidFile) : 0;
// posix_kill($master_pid, 0)判断主进程是否还存活.
$master_is_alive = $master_pid && @posix_kill($master_pid, 0) && posix_getpid() != $master_pid;
if ($master_is_alive) {
// 如果主进程存活,输入的是启动命令则退出本次命令操作.
if ($command === 'start') {
self::log("Workerman[$start_file] already running");
exit;
}
} elseif ($command !== 'start' && $command !== 'restart') {
// 如果主进程不存在,输入的命令不是start和restart则退出本次操作.
self::log("Workerman[$start_file] not run");
exit;
}
// execute command.
switch ($command) {
case 'start':
if ($command2 === '-d') {
Worker::$daemonize = true;
}
break;
case 'status':
// 查看服务运行状态.
while (1) {
if (is_file(self::$_statisticsFile)) {
// 统计文件存在则进行删除.
@unlink(self::$_statisticsFile);
}
// 给主进程发送SIGUSR2信号,然后主进程给所有的worker子进程发送SIGUSR2信号,上报自己的信息.
posix_kill($master_pid, SIGUSR2);
// Sleep 1 second.
sleep(1);
// 清空终端(相当于执行了ctrl+l).
if ($command2 === '-d') {
echo "\33[H\33[2J\33(B\33[m";
}
// 将主进程和各个业务状态格式化输出.
echo self::formatStatusData();
// 如果没有带-d参数获取一次就退出,带了-d参数相当于每秒获取一次.
if ($command2 !== '-d') {
exit(0);
}
echo "\nPress Ctrl+C to quit.\n\n";
}
exit(0);
case 'connections':
// 查看客户端连接情况.
if (is_file(self::$_statisticsFile)) {
@unlink(self::$_statisticsFile);
}
// 主进程发送SIGIO信号给各个子进程.
posix_kill($master_pid, SIGIO);
// 等待各个子进程上报数据.
usleep(500000);
// 输出统计信息文件.
@readfile(self::$_statisticsFile);
exit(0);
// 不管是restart还是stop操作,都是要先将老的worker进程杀死.
// restart = stop + start;
case 'restart':
case 'stop':
if ($command2 === '-g') {
self::$_gracefulStop = true;
$sig = SIGTERM;
self::log("Workerman[$start_file] is gracefully stoping ...");
} else {
self::$_gracefulStop = false;
$sig = SIGINT;
self::log("Workerman[$start_file] is stoping ...");
}
// 给主进程发送停止信号.
$master_pid && posix_kill($master_pid, $sig);
// Timeout.
$timeout = 5;
$start_time = time();
// Check master process is still alive?
while (1) {
// 判断旧的主进程是否还存活.
$master_is_alive = $master_pid && posix_kill($master_pid, 0);
if ($master_is_alive) {
// 停止操作超时,本次操作结束.
if (!self::$_gracefulStop && time() - $start_time >= $timeout) {
self::log("Workerman[$start_file] stop fail");
exit;
}
// 等待主进程结束.
usleep(10000);
continue;
}
// Stop success.
self::log("Workerman[$start_file] stop success");
// 如果是停止命令,杀死运行的worker以后,本次执行也结束.
if ($command === 'stop') {
exit(0);
}
// 如果是重启命令,那么是杀死老的worker,程序往下执行,当前进程变主进程.
if ($command2 === '-d') {
Worker::$daemonize = true;
}
break;
}
break;
case 'reload':
if($command2 === '-g'){
$sig = SIGQUIT;
}else{
$sig = SIGUSR1;
}
// worker加载新的配置文件,当前进程结束.
posix_kill($master_pid, $sig);
exit;
default :
exit($usage);
}
}
首先进行的命令检查.
根据不同的命令执行不同的操作.
1. start // 启动.
php file.php start
php file.php start -d // 守护进程方式启动.
核心代码:
$master_pid && @posix_kill($master_pid, 0) && posix_getpid() != $master_pid
// 判断主进程是否存活.
2. stop // 停止.
php file.php stop
php file.php stop -g // 平滑关闭.
核心代码:
// 给主进程发送停止信号.
$master_pid && posix_kill($master_pid, $sig);
// 判断旧的主进程是否还存活.
$master_is_alive = $master_pid && posix_kill($master_pid, 0);
3. restart // 重启:先stop->后start.
php file.php restart
php file.php restart -d
php file.php restart -g
4. reload // 重新加载配置(相当于子进程慢慢重启,保证客户端链接不挂)
php file.php reload
php file.php reload -g
核心代码:
// worker加载新的配置文件,当前进程结束.
posix_kill($master_pid, $sig);
5. status // 查看当前服务运行状态.
php file.php status
php file.php status -d // 每秒获取一次.
核心代码:
// 给主进程发送SIGUSR2信号,然后主进程给所有的worker子进程发送SIGUSR2信号,上报自己的信息.
posix_kill($master_pid, SIGUSR2);
6. connections // 查看客户端连接情况.
php file.php connections
核心代码:
// 主进程发送SIGIO信号给各个子进程.
posix_kill($master_pid, SIGIO);
重点:命令解析方法的核心在于外部传入命令,通过保存的主进程id,向运行的主进程发送信号,从而达到外部控制运行中的worker进程