6、Workerman 基本使用 - Worker 属性与接口 >

作者: 温新

图书: 【Workerman 基本使用】

阅读: 140

时间: 2024-04-22 13:05:21

hi,我是温新,一名 PHPer

本篇文章对 Worker 的属性进行基本的演示使用,这这些属性的详细信息请参考文档。

Worker 属性

<?php
/**
 * worker-attribute.php
 *
 * Worker 属性
 */

use Workerman\Worker;
use Workerman\Connection\TcpConnection;
use Workerman\Timer;

require_once __DIR__ . '/vendor/autoload.php';

$worker = new Worker('tcp://0.0.0.0:8888');

// 设置日志文件
Worker::$logFile = '/tmp/workerman.log';

// 设置启动进程数量
$worker->count = 5;
// 设置进程名称
$worker->name = 'workerman-server';

$worker->onWorkerStart = function(Worker $worker)
{
    // 当前 worker 进程的 id 编号
    echo 'Worker 进程 ID:' .$worker->id . PHP_EOL;

    // 定时,每10秒一次
    Timer::add(10, function() use ($worker) {
        // 遍历当前进程所有的客户端连接,发送当前服务器的时间
        foreach($worker->connections as $connection) {
            $connection->send(time());
        }
    });
};

$worker->onMessage = function (TcpConnection $connection, $data) {

};

Worker::runAll();

测试

$ php worker-attribute.php start
Workerman[worker-attribute.php] start in DEBUG mode
------------------------------------------- WORKERMAN -------------------------------------------
Workerman version:4.1.15          PHP version:8.2.0           Event-Loop:\Workerman\Events\Event
-------------------------------------------- WORKERS --------------------------------------------
proto   user            worker              listen                processes    status           
tcp     codeing         workerman-server    tcp://0.0.0.0:8888    5             [OK]            
-------------------------------------------------------------------------------------------------
Press Ctrl+C to stop. Start success.
Worker 进程 ID:0
Worker 进程 ID:1
Worker 进程 ID:2
Worker 进程 ID:3
Worker 进程 ID:4

查看下指定位置的日志文件

$ cat /tmp/workerman.log 
2024-02-28 14:02:56 pid:51910 Workerman[worker-attribute.php] start in DEBUG mode
2024-02-28 14:03:28 pid:51910 Workerman[worker-attribute.php] stopping ...
2024-02-28 14:03:28 pid:51910 Workerman[worker-attribute.php] has been stopped
2024-02-28 14:04:33 pid:52191 Workerman[worker-attribute.php] start in DEBUG mode
2024-02-28 14:04:47 pid:52191 Workerman[worker-attribute.php] stopping ...
2024-02-28 14:04:47 pid:52191 Workerman[worker-attribute.php] has been stopped
2024-02-28 14:05:31 pid:52306 Workerman[worker-attribute.php] start in DEBUG mode
2024-02-28 14:05:38 pid:52331 Workerman[worker-attribute.php] reload 
2024-02-28 14:05:38 pid:52306 Workerman[worker-attribute.php] reloading
2024-02-28 14:15:07 pid:52306 Workerman[worker-attribute.php] stopping ...
2024-02-28 14:15:07 pid:52306 Workerman[worker-attribute.php] has been stopped
2024-02-28 14:15:08 pid:53709 Workerman[worker-attribute.php] start in DEBUG mode

查看下进行名称

$ ps aux | grep workerman-server | awk '{print $14}'
workerman-server
workerman-server
workerman-server
workerman-server
workerman-server

Worker 接口

根据文档中的案例,来演示 listen 接口。

这个案例是文档中的案例,最重要的是,要去理解这个思路。

<?php
/**
 * worker-list.php
 * 
 * listen 监听
 */

use Workerman\Worker;
use Workerman\Connection\TcpConnection;
require_once __DIR__ . '/vendor/autoload.php';

$worker = new Worker('websocket://0.0.0.0:1234');

// 注意这里进程数必须设置为 1
$worker->count = 1;

// worker 进程启动后创建一个 text Worker 以便打开一个内部通讯端口
$worker->onWorkerStart = function(Worker $worker) {

    // 开启一个内部端口,方便内部系统推送数据,Text 协议格式 文本+换行符
    $inner_text_worker = new Worker('text://0.0.0.0:5678');
    $inner_text_worker->onMessage = function(TcpConnection $connection, $data) use ($worker) {
        // $dataArr 数组格式,里面有 uid,表示向那个 uid 的页面推送数据
        $dataArr = json_decode($data, true);
        $uid = $dataArr['uid'];
        // 通过 workerman,向 uid 的页面推送数据
        $ret = sendMessageByUid($worker, $uid, $data);

        // 返回推送结果
        $connection->send($ret ? 'ok' : 'fail');
    };

    // 执行监听
    $inner_text_worker->listen();
};

// 新增加一个属性,用来保存 uid 到 connection 的映射
$worker->uidConnections = [];

// 当有客户端发来消息时执行的回调函数
$worker->onMessage = function(TcpConnection $connection, $data) use ($worker) {
    // 判断当前客户端是否已经验证,既是否设置了uid
    if(!isset($connection->uid)) {
        // 没验证的话把第一个包当做 uid(这里为了方便演示,没做真正的验证)
        $connection->uid = $data;
        /* 保存 uid 到 connection 的映射,这样可以方便的通过 uid 查找 connection,
         * 实现针对特定 uid 推送数据
         */
        $worker->uidConnections[$connection->uid] = $connection;

        return;
    }
};

// 当有客户端连接断开时
$worker->onClose = function(TcpConnection $connection) use ($worker) {
    if(isset($connection->uid)){
        // 连接断开时删除映射
        unset($worker->uidConnections[$connection->uid]);
    }
};

// 针对uid推送数据
function sendMessageByUid($worker, $uid, $message) {
    // 如果 uid 存在于映射表中,则找到对应的连接并向其发送消息
    if(isset($worker->uidConnections[$uid])) {
        $webConnection = $worker->uidConnections[$uid];
        $webConnection->send($message);

        return true;
    }

    return false;
}

Worker::runAll();

代码解释:

  1. 创建一个 WebSocket 服务器,监听 1234 端口,用于处理客户端的 WebSocket 连接请求。
  2. 在 WebSocket 服务器启动时,创建一个内部通讯 Worker,监听 5678 端口,接收内部系统推送的消息,并通过 uid 将消息转发给相应的 WebSocket 客户端。
  3. 维护一个 uid 到连接的映射表,以便能够通过 uid向 特定用户推送消息。
  4. 提供sendMessageByUid函数,实现根据 uid 查找对应连接并发送消息的功能。

1、启动服务端

$ php worker-list.php start

2、前段接收推送的 JS 代码(可在 F12 中打开执行)

let ws = new WebSocket('ws://127.0.0.1:1234');

ws.onopen = function(){
    let uid = 'uid1';
    ws.send(uid);
};

ws.onmessage = function(e){
    alert(e.data);
};

3、后端推送代码

<?php
// client.php
    
// 建立socket连接到内部推送端口
$client = stream_socket_client('tcp://127.0.0.1:5678', $errno, $errmsg, 1);
// 推送的数据,包含uid字段,表示是给这个uid推送
$data = ['uid'=>'uid1', 'percent'=>'88%'];
// 发送数据,注意5678端口是Text协议的端口,Text协议需要在数据末尾加上换行符
fwrite($client, json_encode($data)."\n");
// 读取推送结果
echo fread($client, 8192);
请登录后再评论