只是更换了服务器,一直报这个错,ws始终连接不上。

建材王哥

问题描述

环境什么都相同,只是更换了一台服务器,运行则出现这个问题,原服务器跟这个一样的。
SendBufferToWorker fail. The connections between Gateway and BusinessWorker are not ready
截图
截图

程序代码

--------------------start_gateway.php--------------------
<?php
require_once __DIR__ . '/vendor/autoload.php';

use GatewayWorker\Gateway;
use Workerman\Worker;

// 初始化 Gateway
$gateway = new Gateway("websocket://0.0.0.0:3301");

// 设置进程数
$gateway->count = 4;

// 设置名称
$gateway->name = 'WebSocketGateway';

// 设置心跳检测
$gateway->pingInterval = 30;
$gateway->pingNotResponseLimit = 1;

--------------------start_businessworker.php--------------------
<?php
require_once __DIR__ . '/vendor/autoload.php';

use GatewayWorker\BusinessWorker;
use Workerman\Worker;

// 初始化 BusinessWorker
$worker = new BusinessWorker();

// 设置名称
$worker->name = 'WebSocketBusinessWorker';

// 设置进程数
$worker->count = 4;

// 设置事件处理类
$worker->eventHandler = 'Events';

--------------------start_http.php--------------------
<?php
require_once __DIR__ . '/vendor/autoload.php';

use Workerman\Worker;
use Workerman\Connection\TcpConnection;
use Workerman\Protocols\Http\Request;
use Workerman\Protocols\Http\Response;
use GatewayWorker\Lib\Gateway;

// 创建 Redis 客户端
$redis = new Redis();
$redis->connect('127.0.0.1', 6379);
// 创建一个 HTTP 服务器,监听 3300 端口
$httpWorker = new Worker('http://0.0.0.0:3300');

// 监听 HTTP 请求事件
$httpWorker->onMessage = function (TcpConnection $connection, Request $request) use ($redis) {
    // 检查请求方法是否为 POST
    if ($request->method() === 'POST') {
        // 获取请求体中的 JSON 数据
        $data = json_decode($request->rawBody(), true);

        // 检查 JSON 数据是否解析成功
        if (json_last_error() === JSON_ERROR_NONE) {

            // 获取请求路径(例如 /pudm)
            $path = $request->path();

            // 从 Redis 中获取该路径对应的客户端 ID
            $clientIds = $redis->get($path);

            if (!empty($clientIds)) {
                Gateway::sendToGroup($path, $request->rawBody());
                // 返回成功响应
                $connection->send(new Response(200, [], json_encode([
                    'status' => 'success',
                    'message' => 'Message forwarded to WebSocket clients'
                ])));
            } else {
                // 没有客户端连接该路径
                $connection->send(new Response(404, [], json_encode([
                    'status' => 'error',
                    'message' => 'No clients connected to this path'
                ])));
            }
        } else {
            // JSON 解析失败
            $connection->send(new Response(400, [], json_encode([
                'status' => 'error',
                'message' => 'Invalid JSON data'
            ])));
        }
    } else {
        // 非 POST 请求
        $connection->send(new Response(405, [], json_encode([
            'status' => 'error',
            'message' => 'Only POST requests are allowed'
        ])));
    }
};

--------------------start_register.php--------------------
<?php
require_once __DIR__ . '/vendor/autoload.php';

use Workerman\Worker;

// 初始化 Register
$register = new Worker('text://0.0.0.0:1237');

// 设置名称
$register->name = 'Register';

--------------------Events.php--------------------
<?php
require_once __DIR__ . '/vendor/autoload.php';

use GatewayWorker\Lib\Gateway;
use Workerman\Connection\TcpConnection;

// 创建 Redis 客户端
$redis = new Redis();
$redis->connect('127.0.0.1', 6379);

class Events
{
    // 当客户端连接时触发
    public static function onConnect($clientId)
    {
        echo "Client {$clientId} connected.\n";
    }

    // 当客户端发送消息时触发
    public static function onMessage($clientId, $message)
    {
        echo "Received message from client {$clientId}: {$message}\n";
        Gateway::sendToAll($message, null, $clientId);
    }

    // 当客户端断开连接时触发
    public static function onClose($clientId)
    {
        echo "Client {$clientId} disconnected.\n";

        // 从 Redis 中移除该客户端 ID
        global $redis;
        $paths = $redis->keys('*');
        foreach ($paths as $path) {
            $redis->sRem($path, $clientId);
        }
    }

    // 当 WebSocket 握手成功时触发
    public static function onWebSocketConnect($clientId, $httpHeader)
    {
        // 从 HTTP 请求头中提取路径
        $path = $httpHeader['server']['REQUEST_URI'];
        Gateway::joinGroup($clientId, $path);
        global $redis;
        $redis->set($path, $clientId);
    }

    // 从 HTTP 请求头中提取路径
    private static function extractPathFromHeader($httpHeader)
    {
        // 查找路径的开始位置
        $start = strpos($httpHeader, 'GET /') + 4;
        // 查找路径的结束位置
        $end = strpos($httpHeader, ' HTTP/1.1');
        // 提取路径
        return substr($httpHeader, $start, $end - $start);
    }
}

操作系统及workerman/webman等框架组件具体版本

截图
截图
截图
PHP版本:8.0.26

321 11 0
11个回答

建材王哥

截图
端口均已放行

  • 暂无评论
建材王哥

额,没人吗

  • 暂无评论
Tinywan

这种一般都是防火墙端口未放行问题

Risin9

检查一下服务器的安全组有没有放行端口

建材王哥

求助,困扰一下午了

建材王哥

求助,求助

  • 暂无评论

registerAddress没配置,
$gateway->registerAddress = '127.0.0.1:1237';
$worker->registerAddress = '127.0.0.1:1237';

另外redis和数据库等初始化放到onWorkerStart里,提前初始化后所有子进程共享redis和数据库连接导致连接断开或数据错乱

  • 建材王哥 5天前

    我试试,感谢。

  • 建材王哥 5天前

    似乎还是不行,registerAddress在gateway和BusinessWorker里面均进行了配置,并且把redis放在onworkerstart里面初始化了,似乎还是这个结果

建材王哥

截图

  • 暂无评论
建材王哥
--------------------Events.php--------------------
<?php
require_once __DIR__ . '/vendor/autoload.php';

use GatewayWorker\Lib\Gateway;
use Workerman\Worker;

class Events
{
    // 当 Worker 进程启动时触发
    public static function onWorkerStart($worker)
    {
        // 创建 Redis 客户端
        global $redis;
        $redis = new Redis();
        $redis->connect('127.0.0.1', 6379);
        echo "Redis connected.\n";
    }

    // 当客户端连接时触发
    public static function onConnect($clientId)
    {
        echo "Client {$clientId} connected.\n";
    }

    // 当客户端发送消息时触发
    public static function onMessage($clientId, $message)
    {
        echo "Received message from client {$clientId}: {$message}\n";
        Gateway::sendToAll($message, null, $clientId);
    }

    // 当客户端断开连接时触发
    public static function onClose($clientId)
    {
        echo "Client {$clientId} disconnected.\n";

        // 从 Redis 中移除该客户端 ID
        global $redis;
        $paths = $redis->keys('*');
        foreach ($paths as $path) {
            $redis->sRem($path, $clientId);
        }
    }

    // 当 WebSocket 握手成功时触发
    public static function onWebSocketConnect($clientId, $httpHeader)
    {
        // 从 HTTP 请求头中提取路径
        $path = $httpHeader['server']['REQUEST_URI'];
        Gateway::joinGroup($clientId, $path);
        var_dump(Gateway::getClientIdCountByGroup($path));

        // 将客户端 ID 存储到 Redis 中
        global $redis;
        $redis->sAdd($path, $clientId);
    }
}

--------------------start_gateway.php--------------------
    <?php
require_once __DIR__ . '/vendor/autoload.php';

use GatewayWorker\Gateway;
use Workerman\Worker;

// 初始化 Gateway
$gateway = new Gateway("websocket://0.0.0.0:3301");

// 设置进程数
$gateway->count = 2;

// 设置名称
$gateway->name = 'WebSocketGateway';

// 设置心跳检测
$gateway->pingInterval = 30;
$gateway->pingNotResponseLimit = 1;
$gateway->registerAddress = '127.0.0.1:1237';

--------------------start_businessworker.php--------------------
<?php
require_once __DIR__ . '/vendor/autoload.php';

use GatewayWorker\BusinessWorker;
use Workerman\Worker;

// 初始化 BusinessWorker
$worker = new BusinessWorker();

// 设置名称
$worker->name = 'WebSocketBusinessWorker';

// 设置进程数
$worker->count = 2;

// 设置事件处理类
$worker->eventHandler = 'Events';
$worker->registerAddress = '127.0.0.1:1237';

--------------------start_http.php--------------------
<?php
require_once __DIR__ . '/vendor/autoload.php';

use Workerman\Worker;
use Workerman\Connection\TcpConnection;
use Workerman\Protocols\Http\Request;
use Workerman\Protocols\Http\Response;
use GatewayWorker\Lib\Gateway;

// 创建一个 HTTP 服务器,监听 3300 端口
$httpWorker = new Worker('http://0.0.0.0:3300');

// 设置 Worker 进程数
$httpWorker->count = 4;

// 当 Worker 进程启动时触发
$httpWorker->onWorkerStart = function ($worker) {
    // 创建 Redis 客户端
    global $redis;
    $redis = new Redis();
    $redis->connect('127.0.0.1', 6379);
    echo "Redis connected in Worker {$worker->id}.\n";
};

// 监听 HTTP 请求事件
$httpWorker->onMessage = function (TcpConnection $connection, Request $request) {
    global $redis;

    // 检查请求方法是否为 POST
    if ($request->method() === 'POST') {
        // 获取请求体中的 JSON 数据
        $data = json_decode($request->rawBody(), true);

        // 检查 JSON 数据是否解析成功
        if (json_last_error() === JSON_ERROR_NONE) {
            // 获取请求路径(例如 /pudm)
            $path = $request->path();

            // 从 Redis 中获取该路径对应的客户端 ID
            $clientIds = $redis->get($path);

            if (!empty($clientIds)) {
                // 转发消息给 WebSocket 客户端
                Gateway::sendToGroup($path, $request->rawBody());

                // 返回成功响应
                $connection->send(new Response(200, [], json_encode([
                    'status' => 'success',
                    'message' => 'Message forwarded to WebSocket clients'
                ])));
            } else {
                // 没有客户端连接该路径
                $connection->send(new Response(404, [], json_encode([
                    'status' => 'error',
                    'message' => 'No clients connected to this path'
                ])));
            }
        } else {
            // JSON 解析失败
            $connection->send(new Response(400, [], json_encode([
                'status' => 'error',
                'message' => 'Invalid JSON data'
            ])));
        }
    } else {
        // 非 POST 请求
        $connection->send(new Response(405, [], json_encode([
            'status' => 'error',
            'message' => 'Only POST requests are allowed'
        ])));
    }
};
  • 暂无评论
建材王哥

滴滴

  • 暂无评论
建材王哥

额,没人吗

  • 暂无评论
×
🔝