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发现:
但我看不太明白打印的这些都是什么,不知道问题处出在哪里。
while (true) {
$connection->send(根据接收到的客户端的$data发送要发送的消息);
usleep(1000000); // 睡1秒
}
业务代码死循环了,这样你的代码一直在死循环在while (true) {}里运行,其它代码都执行不到的,包括onMessage的代码,包括workerman框架的代码都执行不到,所以完全不工作了。C/C++/java等语言都是,死循环是大忌。
谢谢,我明白了。之前我对后端往前端推送消息的逻辑没想清除,以为把发送消息的代码放在一个死循环里一直发送就可以了,现在我把代码改了,前端定时往后端发送消息,后端监听前端的消息,根据前端发送的消息推送对应的消息,这样某个进程就不会一直处于busy状态了。