• Swoole笔记(二)


    本文示例代码详见:https://github.com/52fhy/swoole_demo。

    重新打开日志

    在1.8.11及之后版本支持重新打开日志:向Server主进程发送SIGRTMIN信号。假设主进程id是3427,那么我们可以:

    kill -34 3427
    

    注:SIGRTMIN信号的id是34。通过kill -l查看。

    那么如何利用这个特征实现每天自动写入新的日志文件里面呢?

    假设日志文件是/log/swoole.log,我们可以在每天0点运行shell命令:

    mv /log/swoole.log /log/$(date -d '-1 day' +%y-%m-%d).log
    kill -34 $(ps aux|grep swoole_task|grep swoole_task_matser|grep -v grep|awk '{print $2}') # 找到主进程,需要提前命名
    

    我们也可以把master进程的PID写入到文件

    $server->set(array(
        'pid_file' => __DIR__.'/server.pid',
    ));
    

    在Server关闭时自动删除PID文件。此选项在1.9.5或更高版本可用。

    信号管理

    Swoole支持的信号:

    SIGKILL -9 pid 强制杀掉进程
    SIGUSR1 -10 master_pid 重启所有worker进程
    SIGUSR2 -12 master_pid 重启所有task_worker进程
    SIGRTMIN -34 master_pid 重新打开日志(版本1.8.11+)
    

    master_pid代表主进程pid。示例(假设主进程名称是swoole_server,pid是3427):

    # 杀掉进程swoole_server
    kill -9 $(ps aux|grep swoole_server|grep -v grep|awk '{print $2}')
    
    # 重启swoole_server的worker进程
    kill -10 $(ps aux|grep swoole_server|grep -v grep|awk '{print $2}')
    
    # 重新打开日志
    kill -34 3427
    

    Task

    我们可以在worker进程中投递一个异步任务到task_worker池中。此函数是非阻塞的,执行完毕会立即返回。worker进程可以继续处理新的请求。

    通常会把耗时的任务交给task_worker来处理。

    我们可以通过如下代码判断是Worker进程还是TaskWorker进程:

    function onWorkerStart($serv, $worker_id) {
        if ($worker_id >= $serv->setting['worker_num']) {  //超过worker_num,表示这是一个task进程
    
        }
    }
    

    看一个示例:

    <?php
    $server = new swoole_server("127.0.0.1",8088);
    
    $server->set(array(
    	'daemonize' => false,
    	'reactor_num' => 2,
    	'worker_num' => 1,
    	'task_worker_num' => 1,
    ));
    
    $server->on('start', function ($serv){ 
    	swoole_set_process_name("swoole_task_matser"); //主进程命名
    });
    
    $server->on('connect', function ($serv, $fd){ 
    	echo "client connect. fd is {$fd}
    ";
    });
    
    $server->on('receive', function ($serv, $fd, $from_id, $data){
    	
    	echo sprintf("onReceive. fd: %d , data: %s
    ", $fd, json_encode($data) );
    	
    	$serv->task(json_encode([
    		'fd' => $fd,
    		'task_name' => 'send_email',
    		'email_content' => $data,
    		'email' => 'admin@qq.com'
    	]));
    });
    
    $server->on('close', function ($serv, $fd){
    	echo "client close. fd is {$fd}
    ";
    });
    
    $server->on('task', function (swoole_server $serv, $task_id, $from_id,  $data){
    	echo $data;
    	
    	$data = json_decode($data, true);
    	$serv->send($data['fd'], "send eamil to {$data['email']}, content is : {$data['email_content']}
    ");
    	
    	//echo 'task finished';
    	//return 'task finished';
    	$serv->finish('task finished');
    });
    
    $server->on('finish', function (swoole_server $serv, $task_id, $data){
    	echo 'onFinish:' .$data;
    });
    
    $server -> start();
    

    这里新建了一个tcp服务器,参数里设置worker_num进程为1,task_worker_num为1。

    配置了task_worker_num参数后将会启用task功能,swoole_server务必要注册onTask/onFinish2个事件回调函数。如果没有注册,服务器程序将无法启动。

    onTask回调接收4个参数,分别是serv对象、任务ID、自于哪个worker进程、任务的内容。注意的是,$data必须是字符串。我们可以在worker进程里使用swoole_server->task ($data)进行任务投递。

    onFinish回调用于将处理结果告知worker进程,此回调必须有,但是否被调用由OnTask决定。在OnTask里使用return或者finish()可以将处理结果发生到onFinish回调,否则onFinish回调是不会被调用的。也就是说:finish()是可选的。如果worker进程不关心任务执行的结果,不需要调用此函数。onFinish回调里的$data同样必须是字符串。

    我们新起一个窗口,使用telnet发送消息到服务端进行测试:
    client端:

    telnet 127.0.0.1 8088
    Trying 127.0.0.1...
    Connected to 127.0.0.1.
    
    hhh
    send eamil to admin@qq.com, content is : hhh
    

    server端:

    client connect. fd is 1
    onReceive. fd: 1 , data: "hhh
    "
    {"fd":1,"task_name":"send_email","email_content":"hhh
    ","email":"admin@qq.com"}
    onFinish:task finished
    

    onFinish回调里不使用return或者finish(),我们将看不到server端最后一行输出。

    此时服务器进程模型:

    pstree -ap | grep swoole
      |   |       `-php,3190 swoole_task.php
      |   |           |-php,3192 swoole_task.php
      |   |           |   |-php,3194 swoole_task.php
      |   |           |   `-php,3195 swoole_task.php
    

    看到两个worker进程,其中一个是worker进程,另外一个是task_worker进程。

    定时器

    Swoole提供强大的异步毫秒定时器,基于timerfd+epoll实现。主要方法:
    1、swoole_timer_tick:周期性定时器,类似于JavaScript里的setInterval()
    2、swoole_timer_after:一次性定时器。
    3、swoole_timer_clear:清除定时器。

    # 周期性定时器
    int swoole_timer_tick(int $ms, callable $callback, mixed $user_param);
    
    # 一次性定时器
    swoole_timer_after(int $after_time_ms, mixed $callback_function, mixed $user_param);
    
    # 清除定时器
    bool swoole_timer_clear(int $timer_id)
    
    # 定时器回调函数
    function callbackFunction(int $timer_id, mixed $params = null);
    

    注意:

    • $ms 最大不得超过 86400000。
    • manager进程中不能添加定时器。
    • 建议在WorkerStart回调里写定时器。

    定时器示例:

    $server->on('WorkerStart', function (swoole_server $server, $worker_id){
        if ($server->worker_id == 0){//防止重复
            //每隔2000ms触发一次
            swoole_timer_tick(2000, function ($timer_id) {
                echo "tick-2000ms
    ";
            });
            
            //3000ms后执行此函数
            swoole_timer_after(3000, function () {
                echo "after 3000ms.
    ";
            });
        }
    });
    
  • 相关阅读:
    爬虫的基本原理
    爬虫的分类
    gcc编译
    C++字符串总结
    PE文件格式学习笔记
    学习SDR过程中的参考网页
    Linux下源码编译安装遇到的问题
    web | jsp考试复习要点整理
    爬虫 | php封装 | file_get_contents
    re | [NPUCTF2020]EzObfus-Chapter2
  • 原文地址:https://www.cnblogs.com/52fhy/p/6935407.html
Copyright © 2020-2023  润新知