Flask SocketIO 实现动态绘图

Flask-SocketIO 是基于 Flask 的一个扩展,用于简化在 Flask 应用中集成 WebSocket 功能。WebSocket 是一种在客户端和服务器之间实现实时双向通信的协议,常用于实现实时性要求较高的应用,如聊天应用、实时通知等,使得开发者可以更轻松地构建实时性要求较高的应用。通过定义事件处理函数,可以实现双向实时通信,为应用提供更加丰富和实时的用户体验。

前端参数拼接

Flask 提供了针对WebSocket的支持插件flask_socketio直接通过pip命令安装即可导入使用,同时前端也需要引入SocketIO.js库文件。

如下代码通过ECharts图表库和WebSocket技术实现了一个实时监控主机CPU负载的动态折线图。通过WebSocket连接到Flask应用中的Socket.IO命名空间,前端通过实时接收后端传来的CPU负载数据,动态更新折线图,展示1分钟、5分钟和15分钟的CPU负载趋势。同时,通过控制台打印实时数据,实现了方便的调试和监控功能。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <script type="text/javascript" src="https://www.lyshark.com/javascript/jquery/3.5.1/jquery.min.js"></script>
    <script type="text/javascript" src="https://www.lyshark.com/javascript/socket.io/socket.io.min.js"></script>
    <script type="text/javascript" src="https://www.lyshark.com/javascript/echarts/5.3.0/echarts.min.js"></script>
</head>
<body>

<div id="Linechart" style="height:500px;width:1200px;border:1px solid #673ab7;padding:10px;"></div>

    <!-- 执行绘图函数-->
    <script type="text/javascript" charset="UTF-8">
        var display = function(time,x,y,z)
        {
            var echo = echarts.init(document.getElementById("Linechart"));
            var option = {
                title: {
                    left: 'left',
                    text: 'CPU 利用表动态监控',
                },
                // 调节大小
                grid: {
                    left: '3%',
                    right: '4%',
                    bottom: '3%',
                    containLabel: true
                },
                // tooltip 鼠标放上去之后会自动出现坐标
                tooltip: {
                    trigger: 'axis',
                    axisPointer: {
                        type: 'cross',
                        label: {
                            backgroundColor: '#6a7985'
                        }
                    }
                },
            legend: {
                data: ['1分钟负载', '5分钟负载', '15分钟负载']
            },

            xAxis: {
                type: 'category',
                // data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
                data: time
            },
            yAxis: {
                type: 'value'
            },
            series:
            [
                {
                    name: "1分钟负载",
                    stack: "总量",
                    //data: [10, 25, 99, 87, 54, 66, 2],
                    data: x,
                    type: 'line',
                    areaStyle: {}
                },
                {
                    name: "5分钟负载",
                    stack: "总量",
                    //data: [89, 57, 85, 44, 25, 4, 54],
                    data: y,
                    type: 'line',
                    areaStyle: {}
                },
                {
                    name: "15分钟负载",
                    stack: "总量",
                    //data: [1, 43, 2, 12, 5, 4, 7],
                    data: z,
                    type: 'line',
                    areaStyle: {}
                }
            ]
            };
            echo.setOption(option,true);
        }
    </script>

    <!-- 负责对参数的解析,填充数据 -->
    <script type="text/javascript" charset="UTF-8">
        var time =["","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","",""];
        var cpu_load1 = [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0];
        var cpu_load5 = [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0];
        var cpu_load15 = [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0];

        var update_function = function(recv)
        {
            time.push(recv.datetime);
            cpu_load1.push(parseFloat(recv.load1));
            cpu_load5.push(parseFloat(recv.load5));
            cpu_load15.push(parseFloat(recv.load15));

            if(time.length >=10)
            {
                time.shift();
                cpu_load1.shift();
                cpu_load5.shift();
                cpu_load15.shift();

                console.log("时间数组: " + time);
                console.log("1分钟: " + cpu_load1);
                console.log("5分钟: " + cpu_load5);
                console.log("15分钟: " + cpu_load15);

                // 调用绘图函数
                display(time,cpu_load1,cpu_load5,cpu_load15);
            }
        };
    </script>

    <!-- 负责接收目标主机的CPU负载情况 -->
   <script type="text/javascript" charset="UTF-8">
        $(document).ready(function()
        {
            namespace = '/Socket';
            var socket = io.connect("http://" + document.domain + ":" + location.port + namespace);
            socket.emit("message",{"data":"hello lyshark"});  // 初始化完成后,发送一条消息.
            socket.on('response', function(recv) {
                console.log("时间: " + recv.datetime);
                console.log("1分钟: " + recv.load1);
                console.log("5分钟: " + recv.load5);
                console.log("15分钟: " + recv.load15);

                // 调用函数完成数据填充
                update_function(recv);
            });
        });
    </script>
</body>
</html>

后台代码使用Flask和Flask-SocketIO搭建了一个实时监控主机CPU负载的WebSocket应用,并将数据通过socketio.emit函数将数据推送给前端展示。

关键点概括如下:

Flask和SocketIO集成:

  • 使用Flask框架创建了一个Web应用,并通过Flask-SocketIO集成了WebSocket功能,实现了实时双向通信。

消息接收与实时推送:

  • 定义了socket事件处理函数,用于接收前端通过WebSocket发送的消息。在无限循环中,通过socketio.sleep方法设置每2秒推送一次实时的CPU负载数据给前端。

前端连接和断开事件:

  • 定义了connectdisconnect事件处理函数,分别在WebSocket连接建立和断开时触发。在控制台打印相应信息,用于监控连接状态。

实时数据推送:

  • 使用socketio.emit方法实时将CPU负载数据推送给前端,以更新折线图。推送的数据包括当前时间、1分钟负载、5分钟负载和15分钟负载。

前端页面渲染:

  • 通过Flask的render_template方法渲染了一个HTML页面,用于展示实时更新的CPU负载折线图。

调试信息输出:

  • 在每个事件处理函数中使用print语句输出调试信息,方便监测WebSocket连接和消息的传递过程。

总体来说,该应用实现了一个简单而实用的实时监控系统,通过WebSocket技术实时推送主机CPU负载数据至前端,为用户提供了实时可视化的监控体验。

from flask import Flask,render_template,request
from flask_socketio import SocketIO
import time,psutil

async_mode = None
app = Flask(__name__)
app.config['SECRET_KEY'] = "lyshark"
socketio = SocketIO(app)

@app.route("/")
def index():
    return render_template("index.html")

# 出现消息后,率先执行此处
@socketio.on("message",namespace="/Socket")
def socket(message):
    print("接收到消息:",message['data'])

    while True:
        socketio.sleep(2)
        data = time.strftime("%M:%S",time.localtime())
        cpu = psutil.cpu_percent(interval=None,percpu=True)

        socketio.emit("response",
                      {"datetime": data, "load1": cpu[0], "load5": cpu[1], "load15": cpu[2]},
                      namespace="/Socket")

# 当websocket连接成功时,自动触发connect默认方法
@socketio.on("connect",namespace="/Socket")
def connect():
    print("链接建立成功..")

# 当websocket连接失败时,自动触发disconnect默认方法
@socketio.on("disconnect",namespace="/Socket")
def disconnect():
    print("链接建立失败..")

if __name__ == '__main__':
    socketio.run(app,debug=True)

运行后,即可输出当前系统下CPU的负载情况,如下图所示;

后端参数拼接

如上所示的代码是在前端进行的数据拼接,如果我们想要在后端进行数据的拼接,则需要对代码进行一定的改进。

前端编写以下代码,通过WebSocket建立通信隧道,而后台则每隔2秒向前台推送传递字典数据。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <script type="text/javascript" src="https://www.lyshark.com/javascript/jquery/3.5.1/jquery.min.js"></script>
    <script type="text/javascript" src="https://www.lyshark.com/javascript/socket.io/socket.io.min.js"></script>
    <script type="text/javascript" src="https://www.lyshark.com/javascript/echarts/5.3.0/echarts.min.js"></script>
</head>
<body>

<div id="Linechart" style="height:500px;width:1200px;border:1px solid #673ab7;padding:10px;"></div>

    <!-- 执行绘图函数-->
    <script type="text/javascript" charset="UTF-8">
        var display = function(time,x,y,z)
        {
            var echo = echarts.init(document.getElementById("Linechart"));
            var option = {
                title: {
                    left: 'left',
                    text: 'CPU 利用表动态监控',
                },
                // 调节大小
                grid: {
                    left: '3%',
                    right: '4%',
                    bottom: '3%',
                    containLabel: true
                },
                // tooltip 鼠标放上去之后会自动出现坐标
                tooltip: {
                    trigger: 'axis',
                    axisPointer: {
                        type: 'cross',
                        label: {
                            backgroundColor: '#6a7985'
                        }
                    }
                },
            legend: {
                data: ['1分钟负载', '5分钟负载', '15分钟负载']
            },

            xAxis: {
                type: 'category',
                // data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
                data: time
            },
            yAxis: {
                type: 'value'
            },
            series:
            [
                {
                    name: "1分钟负载",
                    stack: "总量",
                    //data: [10, 25, 99, 87, 54, 66, 2],
                    data: x,
                    type: 'line',
                    areaStyle: {}
                },
                {
                    name: "5分钟负载",
                    stack: "总量",
                    //data: [89, 57, 85, 44, 25, 4, 54],
                    data: y,
                    type: 'line',
                    areaStyle: {}
                },
                {
                    name: "15分钟负载",
                    stack: "总量",
                    //data: [1, 43, 2, 12, 5, 4, 7],
                    data: z,
                    type: 'line',
                    areaStyle: {}
                }
            ]
            };
            echo.setOption(option,true);
        }
    </script>

    <!-- 负责接收目标主机的CPU负载情况 -->
   <script type="text/javascript" charset="UTF-8">
        $(document).ready(function()
        {
            namespace = '/Socket';
            var socket = io.connect("http://" + document.domain + ":" + location.port + namespace);
            socket.emit("message",{"data":"hello lyshark"});  // 初始化完成后,发送一条消息.
            socket.on('response', function(recv) {
                console.log("时间: " + recv.datetime);
                console.log("1分钟: " + recv.load1);
                console.log("5分钟: " + recv.load5);
                console.log("15分钟: " + recv.load15);

                // 调用绘图函数
                display(recv.datetime,recv.load1,recv.load5,recv.load15);
            });
        });
    </script>
</body>
</html>

后台代码则是收集数据,并将数据通过socketio.emit函数,推送给前端。

from flask import Flask,render_template,request
from flask_socketio import SocketIO
import time,psutil

async_mode = None
app = Flask(__name__)
app.config['SECRET_KEY'] = "lyshark"
socketio = SocketIO(app)

# 填充数据表
local_time = ["", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", ""]
cpu_load1 = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
cpu_load5 = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
cpu_load15 = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]

# 左移填充
def shift(Array, Size, Push):
    if len(Array) <= Size and len(Array) >= 0:
        Array.pop(0)
        Array.append(Push)
        return True
    return False

# 右移填充
def unshift(Array, Size, Push):
    if len(Array) <= Size and len(Array) >= 0:
        Array.pop(Size-1)
        Array.insert(0,Push)

@app.route("/")
def index():
    return render_template("index.html")

# 出现消息后,率先执行此处
@socketio.on("message",namespace="/Socket")
def socket(message):
    print("接收到消息:",message['data'])
    while True:
        socketio.sleep(1)
        data = time.strftime("%M:%S",time.localtime())
        cpu = psutil.cpu_percent(interval=None,percpu=True)

        # 实现数组最大35,每次左移覆盖第一个
        shift(local_time,35,data)
        shift(cpu_load1,35,cpu[0])
        shift(cpu_load5, 35, cpu[1])
        shift(cpu_load15, 35, cpu[2])

        socketio.emit("response",
                      {"datetime": local_time, "load1": cpu_load1, "load5": cpu_load5, "load15": cpu_load15},
                      namespace="/Socket")

# 当websocket连接成功时,自动触发connect默认方法
@socketio.on("connect",namespace="/Socket")
def connect():
    print("链接建立成功..")

# 当websocket连接失败时,自动触发disconnect默认方法
@socketio.on("disconnect",namespace="/Socket")
def disconnect():
    print("链接建立失败..")

if __name__ == '__main__':
    socketio.run(app,debug=True)

运行动态图如下所示;

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/205026.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

#zookeeper集群+kafka集群

kafka3.0之前是依赖于zookeeper的。 zookeeper是开源&#xff0c;分布式的架构。提供协调服务&#xff08;Apache项目&#xff09; 基于观察者模式涉及的分布式服务管理架构。 存储和管理数据。分布式节点上的服务接受观察者的注册。一旦分布式节点上的数据发生变化&#xf…

【Linux学习】文件描述符重定向缓冲区

目录 九.文件描述符 9.1 文件描述符概念 9.2 文件描述符的分配规则 9.3 重定向 9.3.1 常见的重定向操作 9.3.2 重定向的原理 9.4 缓冲区 9.4.1 缓冲区概念 9.4.2 缓冲区刷新策略 9.4.3 C语言的缓冲区在哪里? 九.文件描述符 9.1 文件描述符概念 在上一篇讲到基础IO时,我们说到…

Java项目学生管理系统二查询所有

学生管理 近年来&#xff0c;Java作为一门广泛应用于后端开发的编程语言&#xff0c;具备了广泛的应用领域和丰富的开发资源。在前几天的博客中&#xff0c;我们探讨了如何搭建前后端环境&#xff0c;为接下来的开发工作打下了坚实的基础。今天&#xff0c;我们将进一步扩展我…

10.0 输入输出 I/O

IO操作主要是指使用Java程序完成输入&#xff08;Input&#xff09;、输出&#xff08;Output&#xff09;操作。所谓输入是指将文件内容以数据流的形式读取到内存中&#xff0c;输出是指通过Java程序将内存中的数据写入到文件中&#xff0c;输入、输出操作在实际开发中应用较为…

Rust UI开发(5):iced中如何进行页面布局(pick_list的使用)?(串口调试助手)

注&#xff1a;此文适合于对rust有一些了解的朋友 iced是一个跨平台的GUI库&#xff0c;用于为rust语言程序构建UI界面。 这是一个系列博文&#xff0c;本文是第五篇&#xff0c;前四篇链接&#xff1a; 1、Rust UI开发&#xff08;一&#xff09;&#xff1a;使用iced构建UI时…

Springboot+vue的客户关系管理系统(有报告),Javaee项目,springboot vue前后端分离项目

演示视频&#xff1a; Springbootvue的客户关系管理系统&#xff08;有报告&#xff09;&#xff0c;Javaee项目&#xff0c;springboot vue前后端分离项目 项目介绍&#xff1a; 本文设计了一个基于Springbootvue的前后端分离的客户关系管理系统&#xff0c;采用M&#xff08…

C++学习之继承中修改成员权限细节

看看下面的代码 这是错误的 class A { public:int x 10; }; class B :public A {using A::x;int x 100; };看看函数 class A { public:void fun(){cout << "uuuu" << endl;} }; class B :public A { public:using A::fun;void fun(){cout << …

C++基础——文件操作

文章目录 1 概述2 文本文件2.1 写文件2.1.1 写文件流程2.1.2 文件打开方式 2.2 读文件 3 二进制文件3.1 写文件3.2 读文件 1 概述 程序最基本的操作之一就是文件操作&#xff0c;程序运行时的数据都是临时数据&#xff0c;当程序结束后就不复存在了。通常都是通过文件或其他持…

2000-2021年各省人口密度数据

2000-2021年各省人口密度数据 1、时间&#xff1a;2000-2021年 2、指标&#xff1a;地区、年份、年末常住总人口(万人&#xff09;、面积&#xff08;平方千米&#xff09;、人口密度&#xff08;人/平方千米&#xff09; 3、来源&#xff1a;各省年鉴、统计年鉴、各省统计局…

File类

File 概述 File: 路径 IO流: 传输 路径 相对路径, 绝对路径 File File对象就表示一个路径&#xff0c;可以是文件的路径、也可以是文件夹的路径这个路径可以是存在的&#xff0c;也允许是不存在的 构造方法 代码示例: package FileTest1;import java.io.File;public c…

Verilog 入门(四)(门电平模型化)

文章目录 内置基本门多输入门简单示例 内置基本门 Verilog HDL 中提供下列内置基本门&#xff1a; 多输入门 and&#xff0c;nand&#xff0c;or&#xff0c;nor&#xff0c;xor&#xff0c;xnor 多输出门 buf&#xff0c;not 三态门上拉、下拉电阻MOS 开关双向开关 门级逻辑…

CAN总线学习(STM32的CAN寄存器使用)(笔记二)

CAN总线基础基础知识的文章&#xff1a;CAN总线学习&#xff08;CAN总线基础知识&#xff09;&#xff08;笔记一&#xff09;-CSDN博客 在前面CAN总线基础知识和报文中介绍的是报文内容是比较全面的&#xff0c;STM32在CAN协议的基础上做了一些简单的简化&#xff0c;例如下图…

C++ 抽象类和接口 详解

目录 0 引言1 抽象类2 接口2.1 Java与C接口的区别 &#x1f64b;‍♂️ 作者&#xff1a;海码007&#x1f4dc; 专栏&#xff1a;C专栏&#x1f4a5; 标题&#xff1a;C 抽象类和接口 详解❣️ 寄语&#xff1a;书到用时方恨少&#xff0c;事非经过不知难&#xff01;&#x1f…

Java数据结构之《顺序查找》问题

一、前言&#xff1a; 这是怀化学院的&#xff1a;Java数据结构中的一道难度中等偏下的一道编程题(此方法为博主自己研究&#xff0c;问题基本解决&#xff0c;若有bug欢迎下方评论提出意见&#xff0c;我会第一时间改进代码&#xff0c;谢谢&#xff01;) 后面其他编程题只要我…

【python】当当书籍数据抓取分析与可视化(代码+报告)【独一无二】

&#x1f449;博__主&#x1f448;&#xff1a;米码收割机 &#x1f449;技__能&#x1f448;&#xff1a;C/Python语言 &#x1f449;公众号&#x1f448;&#xff1a;测试开发自动化【获取源码商业合作】 &#x1f449;荣__誉&#x1f448;&#xff1a;阿里云博客专家博主、5…

06_MySQL数据库高可用解决方案(MHA)

各位道友好&#xff0c;鼠鼠我呀校招刚通过了移动的面试 &#xff0c;但是安排的岗位是偏远县城里面的岗位&#xff0c;各位能给给建议吗&#xff1f;鼠鼠我啊真不想有时候变成销售员去卖产品&#xff01;&#xff01;&#xff01; 任务背景 一、真实案例 公司现在需要做MySQ…

什么是木马

木马 1. 定义2. 木马的特征3. 木马攻击流程4. 常见木马类型5. 如何防御木马 1. 定义 木马一名来源于古希腊特洛伊战争中著名的“木马计”&#xff0c;指可以非法控制计算机&#xff0c;或在他人计算机中从事秘密活动的恶意软件。 木马通过伪装成正常软件被下载到用户主机&…

全面探索模拟浏览器的Python爬虫工具

更多资料获取 &#x1f4da; 个人网站&#xff1a;ipengtao.com Python爬虫是获取网页信息的重要工具&#xff0c;但有时网站对爬虫有限制&#xff0c;要求模拟浏览器行为。本文将深入探讨如何使用Python模拟浏览器行为进行网络数据抓取。我们将介绍相关工具和技术&#xff0c…

docker读取字体异常

解决方法 docker容器中执行 apk add ttf-freefont 根据版本不同 apk add ttf-dejavu-fonts apk add ttf-bernoulli

使用Docker安装Jenkins,解决插件安装失败,版本太低等问题

如果已经遇到插件安装部分失败&#xff0c;Jenkins版本太低&#xff0c;又要换什么清华镜像地址&#xff0c;不要犹豫&#xff0c;直接以下步骤卸载重装就好了 开始安装 yum 更新到最新 yum update到Jenkins官网查找最新的LST版本 最后的版本号一定要带&#xff0c;指定下载具…
最新文章