导读:此节将介绍所有的Swoole的回调函数,每个回调函数都是一个PHP函数,对应一个事件。onStart启动后在主进程(master)的主线程回调此函数function&nbs...
此节将介绍所有的 Swoole 的回调函数,每个回调函数都是一个 PHP 函数,对应一个事件。
启动后在主进程(master)的主线程回调此函数
function onStart(Swoole\Server $server);
参数
功能:Swoole\Server 对象
默认值:无
其它值:无
Swoole\Server $server
在此事件之前 Server 已进行了如下操作
接下来要执行
onStart 回调中,仅允许 echo、打印 Log、修改进程名称。不得执行其他操作 (不能调用 server 相关函数等操作,因为服务尚未就绪)。onWorkerStart 和 onStart 回调是在不同进程中并行执行的,不存在先后顺序。
可以在 onStart 回调中,将 $server->master_pid 和 $server->manager_pid 的值保存到一个文件中。这样可以编写脚本,向这两个 PID 发送信号来实现关闭和重启的操作。
onStart 事件在 Master 进程的主线程中被调用。
在 onStart 中创建的全局资源对象不能在 Worker 进程中被使用,因为发生 onStart 调用时,worker 进程已经创建好了
新创建的对象在主进程内,Worker 进程无法访问到此内存区域
因此全局对象创建的代码需要放置在 Server::start 之前,典型的例子是 Swoole\Table
在 onStart 回调中可以使用异步和协程的 API,但需要注意这可能会与 dispatch_func 和 package_length_func 存在冲突,请勿同时使用。
onStart 回调在 return 之前服务器程序不会接受任何客户端连接,因此可以安全地使用同步阻塞的函数。
SWOOLE_BASE 模式下没有 master 进程,因此不存在 onStart 事件,请不要在 BASE 模式中使用 onStart 回调函数。
WARNING swReactorProcess_start: The onStart event with SWOOLE_BASE is deprecated
此事件在 Server 正常结束前发生
Swoole 版本 >= v4.8.0 可用。在此事件中可以使用协程 API。
function onBeforeShutdown(Swoole\Server $server);
参数
功能:Swoole\Server 对象
默认值:无
其它值:无
Swoole\Server $server
此事件在 Server 正常结束时发生
function onShutdown(Swoole\Server $server);
参数
功能:Swoole\Server 对象
默认值:无
其它值:无
Swoole\Server $server
在此之前 Swoole\Server 已进行了如下操作
强制 kill 进程不会回调 onShutdown,如 kill -9
需要使用 kill -15 来发送 SIGTERM 信号到主进程才能按照正常的流程终止
在命令行中使用 Ctrl+C 中断程序会立即停止,底层不会回调 onShutdown
注意事项
请勿在 onShutdown 中调用任何异步或协程相关 API,触发 onShutdown 时底层已销毁了所有事件循环设施;
此时已经不存在协程环境,如果开发者需要使用协程相关 API 需要手动调用 Co\run 来创建协程容器。
此事件在 Worker 进程 / Task 进程 启动时发生,这里创建的对象可以在进程生命周期内使用。
function onWorkerStart(Swoole\Server $server, int $workerId);
参数
onWorkerStart/onStart 是并发执行的,没有先后顺序
可以通过 $server->taskworker 属性来判断当前是 Worker 进程还是 Task 进程
设置了 worker_num 和 task_worker_num 超过 1 时,每个进程都会触发一次 onWorkerStart 事件,可通过判断 $worker_id 区分不同的工作进程
由 worker 进程向 task 进程发送任务,task 进程处理完全部任务之后通过 onFinish 回调函数通知 worker 进程。例如,在后台操作向十万个用户群发通知邮件,操作完成后操作的状态显示为发送中,这时可以继续其他操作,等邮件群发完毕后,操作的状态自动改为已发送。
下面的示例用于为 Worker 进程 / Task 进程重命名。
$server->on('WorkerStart', function ($server, $worker_id){
global $argv;
if($worker_id >= $server->setting['worker_num']) {
swoole_set_process_name("php {$argv[0]} task worker");
} else {
swoole_set_process_name("php {$argv[0]} event worker");
}
});
如果想使用 Reload 机制实现代码重载入,必须在 onWorkerStart 中 require 你的业务文件,而不是在文件头部。在 onWorkerStart 调用之前已包含的文件,不会重新载入代码。
可以将公用的、不易变的 php 文件放置到 onWorkerStart 之前。这样虽然不能重载入代码,但所有 Worker 是共享的,不需要额外的内存来保存这些数据。onWorkerStart 之后的代码每个进程都需要在内存中保存一份
$worker_id 表示这个 Worker 进程的 ID,范围参考 $worker_id
$worker_id 和进程 PID 没有任何关系,可使用 posix_getpid 函数获取 PID
协程支持
注意
发生致命错误或者代码中主动调用 exit 时,Worker/Task 进程会退出,管理进程会重新创建新的进程。这可能导致死循环,不停地创建销毁进程
此事件在 Worker 进程终止时发生。在此函数中可以回收 Worker 进程申请的各类资源。
function onWorkerStop(Swoole\Server $server, int $workerId);
仅在开启 reload_async 特性后有效。参见 如何正确的重启服务
function onWorkerExit(Swoole\Server $server, int $workerId);
有新的连接进入时,在 worker 进程中回调。
function onConnect(Swoole\Server $server, int $fd, int $reactorId);
接收到数据时回调此函数,发生在 worker 进程中。
function onReceive(Swoole\Server $server, int $fd, int $reactorId, string $data);
参数
关于 TCP 协议下包完整性,参考 TCP 数据包边界问题
例如:代码中可以增加一个 $buffer = array(),使用 $fd 作为 key,来保存上下文数据。 每次收到数据进行字符串拼接,$buffer[$fd] .= $data,然后在判断 $buffer[$fd] 字符串是否为一个完整的数据包。
默认情况下,同一个 fd 会被分配到同一个 Worker 中,所以数据可以拼接起来。使用 dispatch_mode = 3 时,请求数据是抢占式的,同一个 fd 发来的数据可能会被分到不同的进程,所以无法使用上述的数据包拼接方法。
多端口监听,参考此节
当主服务器设置了协议后,额外监听的端口默认会继承主服务器的设置。需要显式调用 set 方法来重新设置端口的协议。
$server = new Swoole\Http\Server("127.0.0.1", 9501);
$port2 = $server->listen('127.0.0.1', 9502, SWOOLE_SOCK_TCP);
$port2->on('receive', function (Swoole\Server $server, $fd, $reactor_id, $data) {
echo "[#".$server->worker_id."]\tClient[$fd]: $data\n";
});
接收到 UDP 数据包时回调此函数,发生在 worker 进程中。
function onPacket(Swoole\Server $server, string $data, array $clientInfo);
TCP 客户端连接关闭后,在 Worker 进程中回调此函数。
function onClose(Swoole\Server $server, int $fd, int $reactorId);
在 task 进程内被调用。worker 进程可以使用 task 函数向 task_worker 进程投递新的任务。当前的 Task 进程在调用 onTask 回调函数时会将进程状态切换为忙碌,这时将不再接收新的 Task,当 onTask 函数返回时会将进程状态切换为空闲然后继续接收新的 Task。
function onTask(Swoole\Server $server, int $task_id, int $src_worker_id, mixed $data);
参数
提示
$server->on('Task', function (Swoole\Server $server, Swoole\Server\Task $task) {
var_dump($task);
$task->finish([123, 'hello']); //完成任务,结束并返回数据
});
此回调函数在 worker 进程被调用,当 worker 进程投递的任务在 task 进程中完成时, task 进程会通过 Swoole\Server->finish() 方法将任务处理的结果发送给 worker 进程。
function onFinish(Swoole\Server $server, int $task_id, mixed $data)
当工作进程收到由 $server->sendMessage() 发送的 unixSocket 消息时会触发 onPipeMessage 事件。worker/task 进程都可能会触发 onPipeMessage 事件
function onPipeMessage(Swoole\Server $server, int $src_worker_id, mixed $message);
参数
功能:消息内容,可以是任意 PHP 类型
默认值:无
其它值:无
功能:消息来自哪个 Worker 进程
默认值:无
其它值:无
功能:Swoole\Server 对象
默认值:无
其它值:无
Swoole\Server $server
int $src_worker_id
mixed $message
当 Worker/Task 进程发生异常后会在 Manager 进程内回调此函数。
此函数主要用于报警和监控,一旦发现 Worker 进程异常退出,那么很有可能是遇到了致命错误或者进程 Core Dump。通过记录日志或者发送报警的信息来提示开发者进行相应的处理。
function onWorkerError(Swoole\Server $server, int $worker_id, int $worker_pid, int $exit_code, int $signal);
参数
功能:进程退出的信号
默认值:无
其它值:无
功能:退出的状态码,范围是 0~255
默认值:无
其它值:无
功能:异常 worker 进程的 pid
默认值:无
其它值:无
功能:异常 worker 进程的 id
默认值:无
其它值:无
功能:Swoole\Server 对象
默认值:无
其它值:无
Swoole\Server $server
int $worker_id
int $worker_pid
int $exit_code
int $signal
常见错误
signal = 11:说明 Worker 进程发生了 segment fault 段错误,可能触发了底层的 BUG,请收集 core dump 信息和 valgrind 内存检测日志,向 Swoole 开发组反馈此问题
exit_code = 255:说明 Worker 进程发生了 Fatal Error 致命错误,请检查 PHP 的错误日志,找到存在问题的 PHP 代码,进行解决
signal = 9:说明 Worker 被系统强行 Kill,请检查是否有人为的 kill -9 操作,检查 dmesg 信息中是否存在 OOM(Out of memory)
如果存在 OOM,分配了过大的内存。1. 检查 Server 的 setting 配置,是否 socket_buffer_size 等分配过大;2. 是否创建了非常大的 Swoole\Table 内存模块。
当管理进程启动时触发此事件
function onManagerStart(Swoole\Server $server);
提示
在 SWOOLE_BASE 模式下,如果设置了 worker_num、max_request、task_worker_num 参数,底层将创建 manager 进程来管理工作进程。因此会触发 onManagerStart 和 onManagerStop 事件回调。
Task 和 Worker 进程已创建
Master 进程状态不明,因为 Manager 与 Master 是并行的,onManagerStart 回调发生是不能确定 Master 进程是否已就绪
在这个回调函数中可以修改管理进程的名称。
在 4.2.12 以前的版本中 manager 进程中不能添加定时器,不能投递 task 任务、不能用协程。
在 4.2.12 或更高版本中 manager 进程可以使用基于信号实现的同步模式定时器
manager 进程中可以调用 sendMessage 接口向其他工作进程发送消息
启动顺序
BASE 模式
当管理进程结束时触发
function onManagerStop(Swoole\Server $server);
Worker 进程 Reload 之前触发此事件,在 Manager 进程中回调
function onBeforeReload(Swoole\Server $server);
参数
功能:Swoole\Server 对象
默认值:无
其它值:无
Swoole\Server $server
Worker 进程 Reload 之后触发此事件,在 Manager 进程中回调
function onAfterReload(Swoole\Server $server);
参数
功能:Swoole\Server 对象
默认值:无
其它值:无
Swoole\Server $server
所有事件回调均在 $server->start 后发生
服务器关闭程序终止时最后一次事件是 onShutdown
服务器启动成功后,onStart/onManagerStart/onWorkerStart 会在不同的进程内并发执行
onReceive/onConnect/onClose 在 Worker 进程中触发
Worker/Task 进程启动 / 结束时会分别调用一次 onWorkerStart/onWorkerStop
onTask 事件仅在 task 进程中发生
onFinish 事件仅在 worker 进程中发生
onStart/onManagerStart/onWorkerStart 3 个事件的执行顺序是不确定的
启用 event_object 后,以下事件回调将使用对象风格
$server->on('Connect', function (Swoole\Server $serv, Swoole\Server\Event $object) {
var_dump($object);
});$server->on('Packet', function (Swoole\Server $serv, Swoole\Server\Packet $object) {
var_dump($object);
});$server->on('PipeMessage', function (Swoole\Server $serv, Swoole\Server\PipeMessage $msg) {
var_dump($msg);
$object = $msg->data;
$serv->sendto($object->address, $object->port, $object->data, $object->server_socket);
});$serv->on('WorkerError', function (Swoole\Server $serv, Swoole\Server\StatusInfo $info) {
var_dump($info);
});$server->on('Task', function (Swoole\Server $serv, Swoole\Server\Task $task) {
var_dump($task);
});$server->on('Finish', function (Swoole\Server $serv, Swoole\Server\TaskResult $result) {
var_dump($result);
});
本文地址:https://www.jinpeng.work/?id=72
若非特殊说明,文章均属本站原创,转载请注明原链接。