swoole学习——6、websocket服务器task异步任务

Task特性的用途

task模块用来做一些异步的慢速任务,比如webim中发广播,发送邮件等。

  • task进程必须是同步阻塞的
  • task进程支持定时器

node.js 假如有10万个连接,要发广播时,那会循环10万次,这时候程序不能做任何事情,不能接受新的连接,也不能收包发包。

而swoole不同,丢给task进程之后,worker进程可以继续处理新的数据请求。任务完成后会异步地通知worker进程告诉它此任务已经完成。

当然task模块的作用还不仅如此,实现PHP的数据库连接池,异步队列等,还需要进一步挖掘。

task底层使用Unix Socket管道通信,是全内存的,没有IO消耗。单进程读写性能可达100万/s,不同的进程使用不同的管道通信,可以最大化利用多核。

代码示例

这里使用swoole创建websocket服务来完成task异步任务的实例,并不局限于websocket服务使用,TCP、UDP、HTTP服务都可使用,举一反三。

服务器端

WsTask.php

<?php
/**
 * User: websockte 基础类
 * FileName: 文件名称
 * Date: 2019/3/23
 * Time: 21:42
 */
class WsTask
{
    CONST HOST = '0.0.0.0'; //IP地址

    CONST POST = 8812;  //端口号

    protected $ws;  //服务器对象

    public function __construct()
    {
        $this->ws = new Swoole\WebSocket\Server(self::HOST,self::POST);
        $this->ws->set([
            'worker_num'=>2,
            'task_worker_num'=>2    //配置此参数后将会启用task功能
        ]);
        $this->ws->on('open',[$this,'on_open']);
        $this->ws->on('message',[$this,'on_message']);
        //使用task任务必须要注册task、finish回调函数
        $this->ws->on('task',[$this,'on_task']);
        $this->ws->on('finish',[$this,'on_finish']);
        $this->ws->on('close',[$this,'on_close']);
        $this->ws->start();
    }


    /**
     * 客户端与服务器成功建立连接 完成握手
     * @param object $server 服务器对象
     * @param object $request   Http对象
     */
    public function on_open($server,$request)
    {
        echo "server: handshake success with fd-{$request->fd}";
    }

    /**
     * 监听客户端发送数据
     * @param object $server 服务器对象
     * @param object $frame 包含客户端信息
     */
    public function on_message($server,$frame)
    {
        echo "receive from {$frame->fd}:{$frame->data},opcode:{$frame->opcode},fin:{$frame->finish}\n";
        //投放task任务到task_worker任务池
        $data = [
            'task'=>1,
            'fd'=>$frame->fd
        ];
        $server->task($data);
        //返回数据给客户端
        $server->push($frame->fd,'hello my name is houguang',1,true);
    }

    /**
     * 执行task任务 返回执行结果到worker进程
     * @param object $sev 服务器对象
     * @param int $taskId task任务ID
     * @param int $workId task任务进程ID
     * @param array $data task任务数据
     */
    public function on_task($sev,$taskId,$workId,$data)
    {
        print_r($data);
        echo "Tasker进程接收到数据,task_id={$taskId}\n";
        echo "正在处理task异步任务....\n";
        //模拟执行10s场景
        sleep(10);
        //返回执行结果到worker进程 调用onFinish回调函数
        return '执行结果return_data';
    }

    /**
     * 将任务处理的结果发送给worker进程
     * @param object $sev 服务器对象
     * @param int $taskId 任务的ID
     * @param $data task任务处理返回的结果内容
     */
    public function on_finish($sev,$taskId,$data)
    {
        echo "接收到Tasker进程处理任务结果,finish_task_id={$taskId}\n";
        echo "返回处理结果给woker进程:{$data}\n";
    }

    /**
     * 服务器发送数据到客户端
     * @param array $message
     * @method push 客户端连接的ID,发送的数据内容,发送数据内容的格式,默认为文本,发送结果bool
     */
    public function push($message)
    {
        $this->ws->push($this->fd,$message);
    }

    /**
     * 断开连接
     * @param object $ser 服务器对象
     * @param int $fd 客户端唯一标识
     */
    public function on_close($ser,$fd)
    {
        echo "client {$fd} closed\n";
    }


}
$server = new WsTask();

函数原型:

Server->task

投递一个异步任务到task_worker池中。此函数是非阻塞的,执行完毕会立即返回。Worker进程可以继续处理新的请求。使用Task功能,必须先设置 task_worker_num,并且必须设置Server的onTask和onFinish事件回调函数(详细说明请参照官网)。

Server->task(mixed $data, int $dst_worker_id = -1);

  • $data要投递的任务数据,必须是可序列化的PHP变量
  • $dst_worker_id可以制定要给投递给哪个Task进程,传入ID即可,范围是0 - (serv->task_worker_num -1)

上面示例通过创建websocket服务来实现task异步任务的使用,当客户端和服务器建立连接后,客户端发送数据到服务端,服务端监听到客户端数据,投递一个异步任务到task_worker池中,模拟耗时任务sleep10秒,然后返回push数据给客户端。

客户端

ws_client.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
Hello My Name is Houguang!!!
</body>
<script>
    //websocket 地址
    var wsUrl = 'ws://X.X.X.X:8812';
    //创建websocket对象实例
    var websocket = new WebSocket(wsUrl);
    
    //成功和websockte服务建立连接 执行回调函数
    websocket.onopen = function (evt) {
        //连接成功 发送数据给服务器
        websocket.send('How are you?');
        console.log('wb_server-connect-success');
    }
    
    //接收服务器返回数据
    websocket.onmessage = function (evt) {
        console.log('ws_server-return-data:'+evt.data);
    }

    //连接关闭
    websocket.onclose = function (evt) {
        console.log('ws_server-close');
    }

    //发送错误
    websocket.onerror = function (evt,err) {
        console.log('ws_server-error-data:'+err);
    }
</script>
</html>
测试

开启websocket服务

php WsTask.php

这里通过使用HTTP服务模拟客户端访问

php HttpServer.php #开启Http服务

浏览器访问 IP地址+端口号(http端口号8811)
在这里插入图片描述
客户端访问直接返回数据并没有延迟10秒,task任务在服务端自动执行

服务端状态 执行task任务
在这里插入图片描述
task任务执行完毕 通知task_worker进程执行结果
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/Hou_guang/article/details/88776501
今日推荐