求助WebSocket opening handshake timed out和dtruss跟踪

beijingde

1,最近在做一个实时监控项目,用到了html5的websocket。场景如下:
点击设备列表,进入某个设备详情页面,监控这个设备的运行状况,实时更新一些设备运行状态参数。

2,前端代码如下:

// 省略...
const socket = new WebSocket(server);

socket.addEventListener('open', function(e) {
    socket.send(该设备id);
});

socket.addEventListener('message', function(e) {
    const data = e.data;

    更新设备信息(data);
});

socket.addEventListener('close', function(e) {
    console.log('websockt连接已关闭');
});

socket.addEventListener('error', function(e) {
    alert("websockt连接发生错误,请刷新页面重试!");
});

// 省略...

3,后端我用的php的wokerman(一个php sokcet服务框架)提供的一个websocket服务用来测试(我目前做前端开发,用这个workerman只是用来测试)。

// 心跳间隔25秒
define('HEARTBEAT_TIME', 25);

$ws_worker = new Worker("websocket://0.0.0.0:9668");

// 8 processes
$ws_worker->count = 8;

// 进程启动后设置一个每秒运行一次的定时器
$ws_worker->onWorkerStart = function($worker) {
    Timer::add(1, function()use($worker){
        $time_now = time();
        foreach($worker->connections as $connection) {
            // 有可能该connection还没收到过消息,则lastMessageTime设置为当前时间
            if (empty($connection->lastMessageTime)) {
                $connection->lastMessageTime = $time_now;
                continue;
            }
            // 上次通讯时间间隔大于心跳间隔,则认为客户端已经下线,关闭连接
            if ($time_now - $connection->lastMessageTime > HEARTBEAT_TIME) {
                $connection->close();
            }
        }
    });
};

// Emitted when data received
$ws_worker->onMessage = function ($connection, $data) {

    // 给connection临时设置一个lastMessageTime属性,用来记录上次收到消息的时间
    $connection->lastMessageTime = time();

    while (true) {
        $connection->send(根据接收到的客户端的$data发送要发送的消息);
        usleep(1000000); // 睡1秒
    }
};

4,现象:
我发现如果刷新设备详情页面8次以上(这个次数正好和后端代码中设置的wokerman的进程数相等),客户端就会连接不上后端的socket服务,一直pending,直到提示:WebSocket opening handshake timed out。而wokerman的运行状态则为:

图片
5,问题:
我想问下我的代码哪里出了问题,是前端js代码或业务逻辑有问题还是后端php代码或业务有问题。
谢谢。

ps:
前后端代码都是跑在本地上,mac os。我看了论坛上和workerman手册上提到可以用strace来跟踪进程,但mac上只有dtruss(貌似是调用的dtrace)可以用,我跟踪了一个busy的进程 sudo dtruss -p 24368发现:

图片
但我看不太明白打印的这些都是什么,不知道问题处出在哪里。

9510 1 0
1个回答

xiuwang

while (true) {
$connection->send(根据接收到的客户端的$data发送要发送的消息);
usleep(1000000); // 睡1秒
}

业务代码死循环了,这样你的代码一直在死循环在while (true) {}里运行,其它代码都执行不到的,包括onMessage的代码,包括workerman框架的代码都执行不到,所以完全不工作了。C/C++/java等语言都是,死循环是大忌。

  • beijingde 2018-02-05

    谢谢,我明白了。之前我对后端往前端推送消息的逻辑没想清除,以为把发送消息的代码放在一个死循环里一直发送就可以了,现在我把代码改了,前端定时往后端发送消息,后端监听前端的消息,根据前端发送的消息推送对应的消息,这样某个进程就不会一直处于busy状态了。

年代过于久远,无法发表回答
🔝