本文示例代码详见: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}\n";
}); $server->on('receive', function ($serv, $fd, $from_id, $data){ echo sprintf("onReceive. fd: %d , data: %s\n", $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}\n";
}); $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']}\n"); //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\r\n"
{"fd":1,"task_name":"send_email","email_content":"hhh\r\n","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\n";
}); //3000ms后执行此函数
swoole_timer_after(3000, function () {
echo "after 3000ms.\n";
});
}
});

Swoole笔记(二)的更多相关文章

  1. 《CMake实践》笔记二:INSTALL/CMAKE_INSTALL_PREFIX

    <CMake实践>笔记一:PROJECT/MESSAGE/ADD_EXECUTABLE <CMake实践>笔记二:INSTALL/CMAKE_INSTALL_PREFIX &l ...

  2. jQuery源码笔记(二):定义了一些变量和函数 jQuery = function(){}

    笔记(二)也分为三部分: 一. 介绍: 注释说明:v2.0.3版本.Sizzle选择器.MIT软件许可注释中的#的信息索引.查询地址(英文版)匿名函数自执行:window参数及undefined参数意 ...

  3. Mastering Web Application Development with AngularJS 读书笔记(二)

    第一章笔记 (二) 一.scopes的层级和事件系统(the eventing system) 在层级中管理的scopes可以被用做事件总线.AngularJS 允许我们去传播已经命名的事件用一种有效 ...

  4. Python 学习笔记二

    笔记二 :print 以及基本文件操作 笔记一已取消置顶链接地址 http://www.cnblogs.com/dzzy/p/5140899.html 暑假只是快速过了一遍python ,现在起开始仔 ...

  5. WPF的Binding学习笔记(二)

    原文: http://www.cnblogs.com/pasoraku/archive/2012/10/25/2738428.htmlWPF的Binding学习笔记(二) 上次学了点点Binding的 ...

  6. webpy使用笔记(二) session/sessionid的使用

    webpy使用笔记(二) session的使用 webpy使用系列之session的使用,虽然工作中使用的是django,但是自己并不喜欢那种大而全的东西~什么都给你准备好了,自己好像一个机器人一样赶 ...

  7. AJax 学习笔记二(onreadystatechange的作用)

    AJax 学习笔记二(onreadystatechange的作用) 当发送一个请求后,客户端无法确定什么时候会完成这个请求,所以需要用事件机制来捕获请求的状态XMLHttpRequest对象提供了on ...

  8. 《MFC游戏开发》笔记二 建立工程、调整窗口

    本系列文章由七十一雾央编写,转载请注明出处.  http://blog.csdn.net/u011371356/article/details/9300383 作者:七十一雾央 新浪微博:http:/ ...

  9. JavaScript基础笔记二

    一.函数返回值1.什么是函数返回值    函数的执行结果2. 可以没有return // 没有return或者return后面为空则会返回undefined3.一个函数应该只返回一种类型的值 二.可变 ...

  10. [Firefly引擎][学习笔记二][已完结]卡牌游戏开发模型的设计

    源地址:http://bbs.9miao.com/thread-44603-1-1.html 在此补充一下Socket的验证机制:socket登陆验证.会采用session会话超时的机制做心跳接口验证 ...

随机推荐

  1. 和我一步步部署 kubernetes 集群

    和我一步步部署 kubernetes 集群 本系列文档介绍使用二进制部署最新 kubernetes v1.6.1 集群的所有步骤,而不是使用 kubeadm 等自动化方式来部署集群: 在部署的过程中, ...

  2. vue实现简单表格组件

    本来想这一周做一个关于vuex的总结的,但是由于朋友反应说还不知道如何用vue去写一个组件,所以在此写写一篇文章来说明下如何去写vue页面或者组件.vue的核心思想就是组件,什么是组件呢?按照我的理解 ...

  3. 图文详解如何快捷搭建LNMP服务环境

    上一篇与大家一起学习了下如何搭建LAMP环境的知识,今天小编再和大家分享下如何快捷地搭建LNMP环境,并搭建起一个网站.Nginx是一个高性能的HTTP和反向代理服务器,也是一个IMAP/POP3/S ...

  4. android studio 2.3 下载地址

      android studio下载:  Windows+SDK:(1.8GB)| Windows(428 MB) | Linux    idea  win.exe  win.zip 序号 名称 中文 ...

  5. 数据库Schema两种含义~~

    1.数据库Schema有两种含义,一种是概念上的Schema,指的是一组DDL语句集,该语句集完整地描述了数据库的结构.还有一种是物理上的 Schema,指的是数据库中的一个名字空间,它包含一组表.视 ...

  6. Java设计模式:桥接模式

    问题提出 生活中有很多事物集合,设为A1,A2......Am ,而每个事物都有功能F1,F2....Fn. 例如邮局的发送业务.简单模拟有两类事物:信件和包裹,均有平邮和挂号邮寄功能.程序设计中如何 ...

  7. CF #228 div1 B. Fox and Minimal path

    题目链接:http://codeforces.com/problemset/problem/388/B 大意是用不超过1000个点构造一张边权为1的无向图,使得点1到点2的最短路的个数为给定值k,其中 ...

  8. cmapx 保存绘制好的图层

    研究了两天,如何保存一绘制好的图层,大致意思都说要使用mapInfo表,然后确定了可定和.TAB表有关.然而网上说的全是垃圾,也不能说全是垃圾,好歹我从中得到了一点点有用的信息,使用mapManage ...

  9. NGINX中的proxy_pass和rewrite

    文章作者:luxianghao 文章来源:http://www.cnblogs.com/luxianghao/p/6807081.html 转载请注明,谢谢合作. 免责声明:文章内容仅代表个人观点,如 ...

  10. openlayers应用“三”:百度地图纠偏

    前两篇文章介绍了openlayers3加载百度在线和离线瓦片地图,页面上能够正常显示.地图加载后在地图上显示一条GPS轨迹,发现离实际位置相差太远,如下图所示: 轨迹形状和实际形状相同,但是位移太远, ...