Swoole多端口监听、热重启以及Timer进阶:简单crontab
最后更新于:2022-04-01 01:09:00
> 环境说明: 系统:Ubuntu14.04 (安装教程包括CentOS6.5)
> PHP版本:PHP-5.5.10
> swoole版本:1.7.7-stable
## **1.多端口监听**
在实际运用场景中,服务器可能需要监听不同host下的不同端口。比如,一个应用服务器,可能需要监听外网的服务端口,同时也需要监听内网的管理端口。在Swoole中,可以轻松的实现这样的功能。 Swoole提供了[addlistener](https://github.com/LinkedDestiny/swoole-doc/blob/master/doc/03.swoole_server%E5%87%BD%E6%95%B0%E5%88%97%E8%A1%A8.md#swoole_serveraddlistener)函数用于给服务器添加一个需要监听的host及port,并指定对应的Socket类型(TCP,UDP,Unix Socket以及对应的IPv4和IPv6版本)。 代码如下:
~~~
$serv = new swoole_server("192.168.1.1", 9501); // 监听外网的9501端口
$serv->addlistener("127.0.0.1", 9502 , SWOOLE_TCP); // 监听本地的9502端口
$serv->start(); // addlistener必须在start前调用
~~~
此时,swoole_server就会同时监听两个host下的两个端口。这里要注意的是,来自两个端口的数据会在同一个onReceive中获取到,这时就要用到swoole的另一个成员函数[connection_info](https://github.com/LinkedDestiny/swoole-doc/blob/master/doc/03.swoole_server%E5%87%BD%E6%95%B0%E5%88%97%E8%A1%A8.md#swoole_serverconnection_info),通过这个函数获取到fd的from_port,就可以判定消息的类型。
~~~
$info = $serv->connection_info($fd, $from_id);
//来自9502的内网管理端口
if($info['from_port'] == 9502) {
$serv->send($fd, "welcome admin\n");
}
//来自外网
else {
$serv->send($fd, 'Swoole: '.$data);
}
~~~
[点此查看完整源码](https://github.com/LinkedDestiny/swoole-doc/blob/master/src/04/swoole_multi_port_server.php)
## **2.服务器热重启**
所谓热重启,就是当服务器相关代码有所变动之后,无需停止服务,而是在服务器仍然运行的状态下更新文件。Swoole通过内置的reload函数以及两个自定义信号量实现了这一功能。 首先我讲解一下Swoole可用的三个信号:SIGTERM,SIGUSR1,SIGUSR2。SIGTERM用于停止服务器,SIGUSR1用于重启全部的Worker进程,SIGUSR2用于重启全部的Task Worker进程。 那要如何实现热更新代码文件呢?Swoole的回调函数中有这个一个回调[onWorkerStart](https://github.com/LinkedDestiny/swoole-doc/blob/master/doc/02.%E4%BA%8B%E4%BB%B6%E5%9B%9E%E8%B0%83%E5%87%BD%E6%95%B0.md#3onworkerstart);该回调会在Worker进程启动时被调用。因此,当swoole_server收到SIGUSR1信号并重启全部Worker进程后,onWorkerStart就会被调用。如果在onWorkerStart中require全部的代码文件,每次onWorkerStart后都会重新require一次php文件,这样就能实现代码文件的热更新。 来看下代码实现:
~~~
public function onStart( $serv ) {
cli_set_process_title("reload_master");
}
public function onWorkerStart( $serv , $worker_id) {
require_once "reload_page.php";
Test(); // reload_page.php中定义的一个函数
}
~~~
首先,在[onStart](https://github.com/LinkedDestiny/swoole-doc/blob/master/doc/02.%E4%BA%8B%E4%BB%B6%E5%9B%9E%E8%B0%83%E5%87%BD%E6%95%B0.md#2onstart)回调函数中通过php的cli_set_process_title函数设置进程名。 在[onWorkerStart](https://github.com/LinkedDestiny/swoole-doc/blob/master/doc/02.%E4%BA%8B%E4%BB%B6%E5%9B%9E%E8%B0%83%E5%87%BD%E6%95%B0.md#3onworkerstart)中,require相关的php文件。 然后,新建一个reload.sh文件,输入如下内容:
~~~
echo "Reloading..."
cmd=$(pidof reload_master)
kill -USR1 "$cmd"
echo "Reloaded"
~~~
这样,就可以通过执行这个脚本重启服务器了。 [点此查看完整源码](https://github.com/LinkedDestiny/swoole-doc/tree/master/src/04/reload)
## **3.Timer补充:after函数**
在swoole-1.7.7stable版本中,Timer新增了一个函数[after](https://github.com/LinkedDestiny/swoole-doc/blob/master/doc/03.swoole_server%E5%87%BD%E6%95%B0%E5%88%97%E8%A1%A8.md#swoole_serverafter)。该函数的作用是在指定的时间间隔后执行回调函数,并且只执行一次。 这个函数可以弥补Timer本身做不到或者做起来很难的一些定时工作。 代码如下:
~~~
$serv->after( 1000 , array($this, 'onAfter') , $str );
~~~
这里指定在1000ms后,执行onAfter回调函数,函数参数为$str。 举个例子,比如服务器要求在收到某个请求后,在30S后向所有用户发起推送。这样的需求就可以直接用after函数来实现。 [点此查看完整源码](https://github.com/LinkedDestiny/swoole-doc/blob/master/src/04/swoole_after_server.php)
## **4.Timer进阶:简易crontab**
未完成