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>

执行步骤

  1. 执行swoole.php文件,php swoole.php
  2. 客户端连接 访问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 协议》,转载必须注明作者和本文链接
《L04 微信小程序从零到发布》
从小程序个人账户申请开始,带你一步步进行开发一个微信小程序,直到提交微信控制台上线发布。
《L03 构架 API 服务器》
你将学到如 RESTFul 设计风格、PostMan 的使用、OAuth 流程,JWT 概念及使用 和 API 开发相关的进阶知识。
讨论数量: 0
(= ̄ω ̄=)··· 暂无内容!

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!