2

一、设置定时器

我们一般处理比较常规的定时任务都会用 Linux 系统自带的定时器 crontab 来执行,但是有时候会满足不了我们的业务需求,达不到毫秒级别,不过Swoole可以帮我们实现。

我们看Swoole官方文档入门指引->快速起步->设置定时器

swoole提供了类似JavaScript的setInterval/setTimeout异步高精度定时器,粒度为毫秒级。使用也非常简单。

  • swoole_timer_tick函数就相当于setInterval,是持续触发的
  • swoole_timer_after函数相当于setTimeout,仅在约定的时间触发一次
  • swoole_timer_tickswoole_timer_after函数会返回一个整数,表示定时器的ID

可以使用 swoole_timer_clear 清除此定时器,参数为定时器ID

二、代码实现

ws_timer.php

<?php

/**
 * WS 优化基础类库
 */

class Ws
{
    public $ws = null;

    CONST HOST = "0.0.0.0";
    CONST PORT = 80;

    public function __construct()
    {
        // static::HOST, static::PORT
        $this->ws = new swoole_websocket_server("0.0.0.0", 80);

        $this->ws->set(
            [

               'enable_static_handler' => true, // 静态资源相关设置
               'document_root' => "/work/study/code/swoole/demo/static", // 存放静态资源路径
              // 'worker_num' => 2,
              // 'task_worker_num' => 2,
            ]
        );

        $this->ws->on("open", [$this, "onOpen"]);
        $this->ws->on("message", [$this, "onMessage"]);
       // $this->ws->on("task", [$this, "onTask"]);
       // $this->ws->on("finish", [$this, "onFinish"]);
        $this->ws->on("close", [$this, "onClose"]);

        $this->ws->start();
    }

    /**
     * 监听ws连接事件
     * @param $ws
     * @param $request
     */
    public function onOpen($ws, $request)
    {
        print_r("Open:" . $request->fd ."\n");

        // 使用定时任务
        if($request->fd == 1)
        {
            // 每2秒执行
            swoole_timer_tick(2000, function($timer_id){
                echo "2s:timerId:{$timer_id}";
            });

        }
    }

    /**
     * 监听ws连接消息
     * @param $ws
     * @param $frame
     */
    public function onMessage($ws, $frame)
    {
        echo "ser-push-message:{$frame->data}\n";

        // TODO::加入我们这个业务需要执行超过 10s,所以,这里可以使用task异步来处理
        $data = [
            'task' => 1,
            'fd' => $frame->fd,
        ];

        // 投递一个任务
        // $ws->task($data);

        // 定时任务,5s后执行,这里是异步任务,不会阻塞,这里使用闭包
        swoole_timer_after(5000, function() use ($ws, $frame){
            echo "5s-after\n";
            $ws->push($frame->fd, "server-time-after");

        });


        $ws->push($frame->fd, "server-push:".date("Y-m-d H:i:s"));

    }

    /**
     * 投递任务
     *
     * @param $serv
     * @param $taskId
     * @param $workerId
     * @param $data
     */
    public function onTask($serv, $task_id, $from_id, $data)
    {
        // 耗时场景 10s
        sleep(10);

        return "on task finish";  // 告诉worker
    }

    public function onFinish($serv, $task_id, $data)
    {
        echo "taskId:{$task_id}\n";

        // 注意:此$data参数为onTask方法返回的结果:on task finish,而不是onTask方法的参数。
        echo "finish-data-success:{$data}\n";

    }

    /**
     * 监听WebSocket连接关闭事件
     *
     * @param $ws
     * @param $fd
     */
    public function onClose($ws, $fd)
    {
        echo "clientid-{$fd} is closed \n";
    }
}

$ws_obj = new Ws();

在服务器端执行该脚本:

root@5ee6bfcc1310:/work/study/code/swoole/demo/server# php ws_timer.php
Open:3
ser-push-message:Hello-Lily
clientid-1 is closed
5s-after
clientid-2 is closed

在浏览器执行客户端代码:ws_task_client.html

clipboard.png

我们可以看到,打开浏览器后,等5秒后,服务器通过定时任务会将 server-time-after 信息推到客户端。



Corwien
6.3k 声望1.6k 粉丝

为者常成,行者常至。