六、Swoole 基础学习笔记 - 深入学习 Tcp Server 运行时参数配置

作者: 温新

分类: 【Swoole 系列】

阅读: 2025

时间: 2023-02-01 13:45:16

hi,我是温新,一名PHPer

文章基于 Swoole 5.0 版本编写。

学习目标:记住 Swoole Tcp 常用配置,了解其他相关配置

说明:本篇文章结合官方文档编写及参考网络资料编写,虽非全部原创,但也是结合了自己的理解,若转载请附带本文 URL,编写不易,持续编写更不易,谢谢!

上篇文章正式对是 Tcp Server 进行了一个记录,本篇文章将学习相关参数的配置。本篇文章将学习常用参数的配置,没有记录的参数请参考官方文档。

set 配置

max_conn

作用:服务器程序,最大允许的连接数(默认值为: ulimit -n)。

如:max_conn => 1000 ,设置 Server 最大允许维持 1000 个 TCP 连接。超过此数量后,新进入的连接将被拒绝。

max_conn 不允许设置太小,最设置的最小值为: (worker_num + task_worker_num) * 2 + 32

max_request

作用:设置 worker 进程的最大任务数。【默认值:0 即不会退出进程】。一个 worker 进程在处理完超过此数值的任务后将自动退出,进程退出后会释放所有内存和资源。

注意:此选项可以用于防止 worker 进程内存溢出。

演示:

<?php
$server->set([
	'worker_num' 	=> 2,
	'reactor_num' 	=> 3,
    // 设置进程最大处理数
	'max_request'	=> 2,
]);

配置好之后,使用另外一个客服端连接服务器,连接成功后向服务端发送数据,然后看看进程的变化:

# 客户端连接之前
$pstree -p 18001
php(18001)─┬─php(18002)─┬─php(18005)
           │            └─php(18006)
           ├─{php}(18003)
           └─{php}(18004)
# 客户端连接之后
$pstree -p 18001
php(18001)─┬─php(18002)─┬─php(18005)
           │            └─php(18087)# 进程发生变化
           ├─{php}(18003)
           └─{php}(18004)
task_worker_num

作用:配置 Task 进程数量。

注意:配置 task_worker_num 参数后,务必在 Server 中注册 onTaskonFinish 事件回调。若没有注册,服务器程序将无法启动。

提示:

  • Task进程是同步阻塞的;
  • 最大值不得超过 swoole_cpu_num() * 1000;
  • 计算方法
    • 单个 task 的处理耗时,如 100ms,那一个进程 1 秒就可以处理 1/0.1=10 个 task;
    • task 投递的速度,如每秒产生 2000task
    • 2000/10=200,需要设置 task_worker_num => 200,启用 200 个 Task 进程。

演示:

<?php
// *** 省略
$server->set([
	'worker_num' 	=> 2,
	'reactor_num' 	=> 3,
	'task_worker_num' => 2,
]);

// 监听异步任务
$server->on('Task', function($server, $taskId, $srcWorkerId, $data) {
});

// 监听异步任务完成
$server->on('Finish', function($server, $taskId, $data) {
});

// *** 省略
daemonize

作用:守护进程化【默认值:false】。设置 daemonize => true 时,程序将转入后台作为守护进程运行。长时间运行的服务器端程序必须启用此项。如果不启用守护进程,当 ssh 终端退出后,程序将被终止运行。

提示:

  • 启用守护进程后,标准输入和输出会被重定向到 log_file
  • 如果未设置 log_file,将重定向到 /dev/null,所有打印屏幕的信息都会被丢弃;
  • 启用守护进程后,CWD(当前目录)环境变量的值会发生变更,相对路径的文件读写会出错。PHP 程序中必须使用绝对路径。
$server->set([
    daemonize => true,
]);

方法

on

作用:用于注册 Server 的事件回调函数。

在之前的文章中见到它的次数很多了,监听某个事件回调就用它。要注意的是,重复调用同一个事件时,新的覆盖旧的,如下案例:

// 旧的
$server->on('Task', function($server, $taskId, $srcWorkerId, $data) {
});
// 新的
$server->on('Task', function($server, $taskId, $srcWorkerId, $data) {
});
start

作用:启动服务器,监听所有 TCP/UDP 端口。

reload

作用:安全地重启所有 Worker/Task 进程。

stop

作用:使当前 Worker 进程停止运行,并立即触发 onWorkerStop 回调函数。

shutdown

作用:关闭服务。

close

作用:关闭客户端连接。

send

作用:向客户端发送数据。

sendfile

发送文件到 TCP 客户端连接。

sendto

作用:向任意的客户端 IP:PORT 发送 UDP 数据包。

sendMessage

作用:向任意 worker 进程或 task 进程发送消息。在非主进程和管理进程中可调用。收到消息的进程会触发 onPipeMessage 事件。

exists

作用:检测 fd 对应的连接是否存在。

getClientInfo

作用:获取连接的客户端信息。

getClientList

作用:遍历当前 Server 所有的客户端连接,Server::getClientList 方法是基于共享内存的,不存在 IOWait,遍历的速度很快。另外 getClientList 会返回所有 TCP 连接,而不仅仅是当前 Worker 进程的 TCP 连接。别名是 Swoole\Server->connection_list()

getWorkerId

作用:获取当前 Worker 进程 id(非进程的 PID)。

getWorkerPid

作用:获取当前 Worker 进程 PID

getWorkerStatus

作用:获取 Worker 进程状态。

getManagerPid

作用:获取当前服务的 Manager 进程 PID

getMasterPid

作用:获取当前服务的 Master 进程 PID

案例演示

使用 send 向客户端发送消息

<?php

$server = new Swoole\Server('0.0.0.0', 9501, SWOOLE_PROCESS, SWOOLE_SOCK_TCP);

$server->on('Receive', function ($server, $fd, $reactorId, $data) {
	// 向客服端发送数据
	$server->send($fd, 'Server:Hello ' . $fd . ' ,你发送的消息是: ' . $data) . PHP_EOL;
});

$server->start();

使用 sendFile 发送文件信息

<?php

$server = new Swoole\Server('0.0.0.0', 9501, SWOOLE_PROCESS, SWOOLE_SOCK_TCP);

$server->on('Receive', function ($server, $fd, $reactorId, $data) {
	// 向客服端发送文件信息
	$server->sendFile($fd, './message.txt');
});

$server->start();

属性

setting

作用:获取 set() 函数设置的所有参数

演示:

<?php
// 其他的省略
$server->set([
	'worker_num' 	=> 2,
	'reactor_num' 	=> 3,
	'task_worker_num' => 2,
]);

$server->on('Start', function($server) {
	print_r($server->setting);
});

输出结果如下:

$php 3-swoole-tcp-param.php 
Array
(
    [worker_num] => 2
    [reactor_num] => 3
    [task_worker_num] => 2
    [output_buffer_size] => 4294967295
    [max_connection] => 1024
)
$master_pid

作用:返回当前服务器主进程的 PID

$manager_id

作用:返回当前服务器管理进程的 PID

$worker_id

作用:获取当前 Worker 进程的编号,包含 Task 进程

$worker_pid

作用:获取当前 Worker 进程的操作系统进程 ID。

$taskworker

作用:当前进程是否是 Task 进程

返回值:boolean。true 表示当前进程是 Task 进程;false 表示当前进程是 Worker 进程。

$connections

作用:包含所有 TCP 连接

综合演示:

<?php
$server = new Swoole\Server('0.0.0.0', 9501, SWOOLE_PROCESS);

$server->set([
	'worker_num' 	=> 2,
	'reactor_num' 	=> 3,
	'task_worker_num' => 2,
]);

$server->on('Connect', function ($server, $fd, $reactorId) {
        echo $fd . ' 连接了' . PHP_EOL;
});

$server->on('Start', function($server) {
});

$server->on('Receive', function ($server, $fd, $fromId, $data) {
	echo '主进程 ' . $server->master_pid . PHP_EOL;
	echo '管理进程 ' . $server->manager_pid . PHP_EOL;
	// 当前客户端连接的 Worker PID
	echo 'workerPid 进程 ' . $server->worker_pid . PHP_EOL;
	echo 'worker 进程 ' . $server->worker_id . PHP_EOL;
	
	foreach ($server->connections as $fd) {
		echo $fd . PHP_EOL;
	}
});

$server->on('Workerstart', function ($server) {
	if ($server->taskworker) {
		echo 'task pid ' . $server->worker_pid . PHP_EOL;
	} else {
		echo 'worker pid' . $server->worker_pid . PHP_EOL;
	}
});

// 监听异步任务
$server->on('Task', function($server, $taskId, $srcWorkerId, $data) {
});

// 监听异步任务完成
$server->on('Finish', function($server, $taskId, $data) {

});

$server->on('Close', function ($server,$fd) {
});

$server->start();

事件

onStart

作用:启动后在主进程(master)的主线程回调此函数

onStart 回调中,仅允许 echo、打印 Log、修改进程名称。不得执行其他操作 (不能调用 server 相关函数等操作,因为服务尚未就绪)。onWorkerStartonStart 回调是在不同进程中并行执行的,不存在先后顺序。

onWorkerStart

作用:此进程在 Worker 进程 / Task 进程启动时发生,这里创建的对象可以在进程生命周期内使用。

注意:onWorkerStart/onStart 是并发执行的,没有先后顺序。可以通过 taskworker 属性来判断是 worker 进程还是 task 进程。

onWorkerStop

作用:此事件在 Worker 进程终止时发生。在此函数中可以回收 Worker 进程申请的各类资源。

注意: 进程异常结束,如被强制 kill、致命错误、core dump 时无法执行 onWorkerStop 回调函数。

onConnect

作用:有新的连接进入时,在 worker 进程中回调。

注意:onConnect/onClose2 个回调发生在 Worker 进程内,而不是主进程。

onReceive

作用:接收到数据时回调此函数,发生在 worker 进程中。

onPacket

作用:接收到 UDP 数据包时回调此函数,发生在 worker 进程中。

UDP 服务中,只需要监听这一个事件即可。

onTask

作用:在 task 进程内被调用。worker 进程可以使用 task 函数向 task_worker 进程投递新的任务。当前的 task 进程在调用 onTask 回调时会将进程状态切换为忙碌,这时将不再接收新的 task,当 onTask 函数返回时会将进程状态切换为空闲然后继续接收新的 Task

onFinish

作用:此回调函数在 worker 进程被调用,当 worker 进程投递的任务在 task 进程中完成时,task 进程会通过 finish() 方法将任务处理的结果发送给 worker 进程。

onPipeMessage

作用:当工作进程收到由 $server->sendMessage() 发送的 unixSocket 消息时会触发 onPipeMessage 事件。worker/task进程都可能会触发onPipeMessage` 事件

onWorkerError

作用:当 Worker/Task 进程发生异常后会在 Manager 进程内回调此函数。

onManagerStart

作用:当管理进程启动时触发此事件

onManagerStop
onBeforeReload

作用:Worker 进程 Reload 之前触发此事件,在 Manager 进程中回调

onAfterReload

作用:Worker 进程 Reload 之后触发此事件,在 Manager 进程中回调

onShutdown

作用:此事件在 Server 正常结束时发生

onBeforeShutdown

作用:此事件在 Server 正常结束前发生

演示:

修改进程名称

<?php

$server = new Swoole\Server('0.0.0.0', 9501, SWOOLE_PROCESS);

$server->set([
    'worker_num' 	 => 3,
    'task_worker_num'=> 2,
]);

$server->on('Connect', function ($server, $fd) {
});

$server->on('Receive', function ($server, $fd, $reactorId, $data) {
});

// 设置 task 进程后,必须调用任务回调,不然会报错
$server->on('Task', function (Swoole\Server $server, Swoole\Server\Task $task) {
});

// 启动 master 进程时,设置进程名称
$server->on('Start', function ($server) {
    swoole_set_process_name('swoole:master');
});

// 管理进程启动时,设置名称
$server->on('ManagerStart', function ($server) {
    swoole_set_process_name('swoole:manager');
});

// worker 进程启动时,回调该事件,在这里我们对进程这是名称
$server->on('WorkerStart', function ($server, $workerId) {
    if($workerId >= $server->setting['worker_num']) {
        swoole_set_process_name("swoole:task worker");
    } else {
        swoole_set_process_name("swoole:php worker");
    }
});

$server->on('Close', function ($server, $fd) {
});

$server->start();

进程之前发送消息

<?php
// 进程之间发送消息

$server = new Swoole\Server('0.0.0.0', 9501, SWOOLE_PROCESS);

$server->set([
    'worker_num' => 5,
    'reactor_num' => 3,
]);

$server->on('Receive', function ($server, $fd, $reactorId, $data) {
	// 向其他进程发送消息
	$server->sendMessage('hello', 1 - $server->worker_id);
});

// 监听管道,接收其他 进程发送的消息
$server->on('pipeMessage', function ($server, $srcWorkerId, $data) {
	echo 'pipeMessage #' . $server->worker_id . ' message from #' . $srcWorkerId . $data . PHP_EOL;
});

$server->start();

输出结果:pipeMessage #1 message from #0hello

本篇文章至此就结束了,我是温新,我们下一篇文章见。

请登录后再评论