TP8 中 GatewayWorker 启动说明

背景

这个 TP8 项目里,GatewayWorker 现在采用的是独立入口文件启动,而不是 php think worker:gateway

以前在 TP6 里常见的启动方式是:

php think worker:gateway

但当前这个 TP8 项目实际使用的是:

php start.php start

原因是:

  1. 当前项目使用的是 GatewayWorker 官方启动方式。
  2. TP8 里安装的 topthink/think-worker 并不会直接提供可用的 worker:gateway 命令。
  3. 目前项目已经改成通过 start.php 启动 RegisterGatewayBusinessWorker

当前启动方式

先进入项目目录:

cd /Users/wfsever/Desktop/代码/tyx/tp8

启动:

php start.php start

后台启动:

php start.php start -d

停止:

php start.php stop

重启:

php start.php restart

查看状态:

php start.php status

查看连接:

php start.php connections

配置文件

GatewayWorker 的统一配置文件是:

config/gateway_worker.php

目前 start.php 会直接读取这份配置,所以以后改端口、worker 数量、register 地址,都只改这里,不要再去改 start.php 里的硬编码。

主要配置项:

'protocol' => 'websocket',
'host' => '0.0.0.0',
'port' => 2348,
'registerAddress' => '127.0.0.1:1236',
'count' => 1,
'lanIp' => '127.0.0.1',
'startPort' => 2000,
'pingInterval' => 55,
'pingNotResponseLimit' => 10,
'businessWorker' => [
    'name' => 'BusinessWorker',
    'count' => 1,
    'eventHandler' => '\app\worker\Events',
],

代码关系

启动入口:
start.php

GatewayWorker 配置:
config/gateway_worker.php

业务事件处理:
app/worker/Events.php

应用内主动推送:
app/service/GatewayPushService.php

当前完整代码

start.php

文件位置:
start.php

<?php
declare(strict_types=1);

use GatewayWorker\BusinessWorker;
use GatewayWorker\Gateway;
use GatewayWorker\Register;
use Workerman\Worker;

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

$missingClasses = array_filter([
    Register::class,
    Gateway::class,
    BusinessWorker::class,
], static fn (string $class): bool => !class_exists($class));

if ($missingClasses) {
    fwrite(STDERR, "GatewayWorker dependency is missing. Run: composer require workerman/gateway-worker\n");
    exit(1);
}

$configFile = __DIR__ . '/config/gateway_worker.php';
if (!is_file($configFile)) {
    fwrite(STDERR, "Gateway config not found: {$configFile}\n");
    exit(1);
}

$config = require $configFile;
if (!is_array($config) || !$config) {
    fwrite(STDERR, "Gateway config is invalid.\n");
    exit(1);
}

$runtimePath = __DIR__ . '/runtime';
if (!is_dir($runtimePath)) {
    mkdir($runtimePath, 0777, true);
}

Worker::$pidFile = $runtimePath . '/gateway-worker.pid';
Worker::$logFile = $runtimePath . '/gateway-worker.log';
Worker::$statusFile = $runtimePath . '/gateway-worker.status';

$registerAddress = (string) ($config['registerAddress'] ?? '127.0.0.1:1236');

if (($config['register_deploy'] ?? true) !== false) {
    new Register('text://' . $registerAddress);
}

if (($config['businessWorker_deploy'] ?? true) !== false) {
    $businessConfig = (array) ($config['businessWorker'] ?? []);

    $businessWorker = new BusinessWorker();
    $businessWorker->name = (string) ($businessConfig['name'] ?? 'BusinessWorker');
    $businessWorker->count = (int) ($businessConfig['count'] ?? 1);
    $businessWorker->registerAddress = $registerAddress;

    if (!empty($businessConfig['eventHandler'])) {
        $businessWorker->eventHandler = ltrim((string) $businessConfig['eventHandler'], '\\');
    }
}

if (($config['gateway_deploy'] ?? true) !== false) {
    $listen = !empty($config['socket'])
        ? (string) $config['socket']
        : sprintf(
            '%s://%s:%d',
            (string) ($config['protocol'] ?? 'websocket'),
            (string) ($config['host'] ?? '0.0.0.0'),
            (int) ($config['port'] ?? 2348)
        );

    $gateway = new Gateway($listen);
    $gateway->name = (string) ($config['name'] ?? 'Gateway');
    $gateway->count = (int) ($config['count'] ?? 1);
    $gateway->registerAddress = $registerAddress;
    $gateway->lanIp = (string) ($config['lanIp'] ?? '127.0.0.1');
    $gateway->startPort = (int) ($config['startPort'] ?? 2000);
    $gateway->pingInterval = (int) ($config['pingInterval'] ?? 0);
    $gateway->pingNotResponseLimit = (int) ($config['pingNotResponseLimit'] ?? 0);
    $gateway->pingData = (string) ($config['pingData'] ?? '');

    if (array_key_exists('context', $config) && is_array($config['context']) && $config['context']) {
        $gateway->context = $config['context'];
    }

    if (array_key_exists('daemonize', $config)) {
        Worker::$daemonize = (bool) $config['daemonize'];
    }
}

Worker::runAll();

config/gateway_worker.php

文件位置:
config/gateway_worker.php

<?php
// +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]
// +----------------------------------------------------------------------
// | Copyright (c) 2006-2018 http://thinkphp.cn All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +----------------------------------------------------------------------
// | Author: liu21st <liu21st@gmail.com>
// +----------------------------------------------------------------------
// +----------------------------------------------------------------------
// | Workerman设置 仅对 php think worker:gateway 指令有效
// +----------------------------------------------------------------------
return [
    // 扩展自身需要的配置
    'protocol' => 'websocket', // 协议 支持 tcp udp unix http websocket text
    'host' => '0.0.0.0', // 监听地址
    'port' => 2348, // 监听端口
    'socket' => '', // 完整监听地址
    'context' => [], // socket 上下文选项
    'register_deploy' => true, // 是否需要部署register
    'businessWorker_deploy' => true, // 是否需要部署businessWorker
    'gateway_deploy' => true, // 是否需要部署gateway

    // Register配置
    'registerAddress' => '127.0.0.1:1236',

    // Gateway配置
    'name' => 'thinkphp',
    'count' => 1,
    'lanIp' => '127.0.0.1',
    'startPort' => 2000,
    'daemonize' => false,
    'pingInterval' => 55,
    'pingNotResponseLimit' => 10,
    'pingData' => '',

    // BusinsessWorker配置
    'businessWorker' => [
        'name' => 'BusinessWorker',
        'count' => 1,
        'eventHandler' => '\app\worker\Events',
    ],

];

运行日志和状态文件

start.php 启动后会使用这些文件:

  1. runtime/gateway-worker.pid
  2. runtime/gateway-worker.log
  3. runtime/gateway-worker.status

如果需要排查启动失败、端口占用、进程状态,优先看这里。

依赖要求

当前项目要求:

  1. PHP 版本为 8.2 及以上
  2. 已安装 workerman/gateway-worker
  3. 已安装 workerman/gatewayclient

composer.json 中相关依赖:

"php": "~8.2",
"workerman/gatewayclient": "^3.1",
"workerman/gateway-worker": "^4.0"

如果缺包,可以在项目目录执行:

composer require workerman/gateway-worker

常见问题

1. 为什么不是 php think worker:gateway

因为当前 TP8 项目不是走老的 ThinkPHP 命令扩展方案,而是走 GatewayWorker 官方独立入口方案。

2. 为什么 start.php 能启动,php think worker:gateway 不行

因为 start.php 是直接启动 GatewayWorker;
php think worker:gateway 依赖 TP 命令注册,这个项目当前并不是靠那条链路运行。

3. 改端口应该改哪里

config/gateway_worker.php,不要直接改 start.php

4. 推送消息连不上 register 怎么办

先确认 config/gateway_worker.php 里的 registerAddress 是否正确,因为 app/service/GatewayPushService.php 会读取它。

建议

后续如果没有特别强的需求,统一按下面这个习惯来:

  1. 启动和停止都用 php start.php ...
  2. GatewayWorker 参数只改 config/gateway_worker.php
  3. 业务事件只改 app/worker/Events.php
  4. 应用内推送只走 GatewayPushService

这样最不容易再绕回“TP6 的老启动方式”和“TP8 当前实现方式”混在一起。

Last modification:April 1, 2026
反正也没人会打赏