swoole 实现控制台监控设备场景
应用场景介绍
- 多个控制台监控多台设备。
直接上代码
服务端代码,swoole.php
<?php
/**
* User: streetlamp
* Date: 2019/1/25
* Time: 10:11
*/
/**
* Class Swoole
* 控制台监控设备的swoole架构,控制台可以同时开启多个并把fd保存到redis,
* 当设备推送消息到swoole服务器时,swoole服务器会把消息广播给控制台集群。
* id参数用来区分项目,type参数为1时该设备为控制台,为2时为普通设备
*/
class Swoole
{
private $ser;
protected $instance = null;
public function __construct()
{
$this->ser = new swoole_websocket_server('0.0.0.0', 9502);
$this->ser->set(array(
'worker_num' => 4,
'max_request' => 50,
'heartbeat_check_interval'=>30,//每隔多少秒检测一次,单位秒,Swoole会轮询所有TCP连接,将超过心跳时间的连接关闭掉
'heartbeat_idle_time'=>60//TCP连接的最大闲置时间,单位s , 如果某fd最后一次发包距离现在的时间超过heartbeat_idle_time会把这个连接关闭。
));
$this->ser->on('WorkerStart', [$this, 'onWorkerStart']);
$this->ser->on('open', [$this, 'onOpen']);
$this->ser->on('message', [$this, 'onMessage']);
$this->ser->on('close', [$this, 'onClose']);
$this->ser->start();
}
public function onWorkerStart($ws, $worker_id)
{
}
public function onOpen($ws, $request)
{
$id = $request->get['id'];
$type = $request->get['type'];
if ($type == 1) {
//把所有控制台fd保存到该项目id的hash表里
$master = $this->redis()->hGetAll($id);
if (empty($master)) {
$this->redis()->hMSet($id, [$request->fd]);
} else {
$master[] = $request->fd;
$this->redis()->hMSet($id, array_unique($master));
}
}
}
public function onMessage($ws, $frame)
{
$data = json_decode($frame->data, true);
if ($data['type'] == 2) {
//收到普通设备推送过来的消息把消息广播给控制台进行数据处理
$master = $this->redis()->hGetAll($data['id']);
$this->broadcast($master, $ws, $data['message'], $data['id']);
}
}
public function onClose($ws, $fd)
{
}
protected function redis()
{
if ($this->instance == null) {
$redis = new \Redis();
$redis->connect('127.0.0.1', 6379);
$this->instance = $redis;
return $this->instance;
} else {
return $this->instance;
}
}
/**
* 广播消息给控制台
* @param $master
* @param $ws
* @param $msg
* @param $id
* @return bool
*/
protected function broadcast($master, $ws, $msg, $id)
{
if (empty($master))
return true;
$del = [];
foreach ($master as $fd) {
if ($ws->exist($fd)) {
$ws->push($fd, $msg);
} else {
$del[] = $fd;
}
}
$result = array_diff($master, $del);
if (!empty($result)) {
$this->redis()->del($id);
$this->redis()->hMSet($id, $result);
}
}
}
new Swoole();
客户端代码 socket.html
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<input type="text" name="message" value="" id="message">
<input type="button" onclick="f()" value="send">
<script>
var id = getQueryString('id');
var type = getQueryString('type');
var ws = new WebSocket('ws://192.168.29.128:9502?id=' + id + '&type=' + type);
ws.onopen = function () {
console.log("onopen");
};
ws.onmessage = function (e) {
console.log(e.data);
};
ws.onclose = function (evt) {
console.log("Disconnected");
};
ws.onerror = function (evt, e) {
console.log('Error occured: ' + evt.data);
};
function f() {
var message = document.getElementById('message').value;
var send = {"message":message,"id":id ,"type":type };
send = JSON.stringify(send)
ws.send(send)
}
function getQueryString(name) {
var reg = new RegExp("(^|&)" + name + "=([^&]*)(&|$)", "i");
var r = window.location.search.substr(1).match(reg);
if (r != null) return unescape(r[2]);
return null;
}
</script>
</body>
</html>
执行步骤
- 执行swoole.php文件,php swoole.php
- 客户端连接 访问socket.html文件,id参数用来区分项目,type参数为1时该设备为控制台,为2时为普通设备。参数通过get方式传递。控制台:localhost/socket.html?type=1&id=a 普通设备:localhost/socket.html?type=2&id=a
- 注意:id是保证控制台和普通设备绑定在一起的参数,所有要保持一致。
streetlamp敬上!
福利:G站-咕噜咕噜影视网
本作品采用《CC 协议》,转载必须注明作者和本文链接