效果图
先看运行效果图
OK,下面开始。
安装环境
本人使用环境及版本:
Anaconda:
虚拟环境:
Python版本:3.8.13
安装包及版本:
Flask-SocketIO:5.3.4
eventlet:0.33.3
快速开始
后端代码
创建app.py文件(文件名随意,不过要与后面的运行脚本中指定的文件保持一致)
import time
from flask import Flask, render_template, jsonify
from flask_socketio import SocketIOservice_state = 0
app = Flask(__name__)
socketio = SocketIO(app, cors_allowed_origins="*")@app.route("/")
def index():return render_template("index.html")@app.route("/start_service")
def start_service():global service_stateservice_state = 0while service_state == 0:time_text = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(int(time.time())))print(">>>>>>", time_text)json_data = {"no": 1, "time": time_text, "msg": "......"}socketio.emit("service_msg", json_data)socketio.sleep(2)return jsonify({"start": True})@app.route("/stop_service")
def stop_service():global service_stateservice_state = 9return jsonify({"stop": True})if __name__ == "__main__":socketio.run(app, host="0.0.0.0", port=5200, debug=True, log_output=True)
前端代码
<!DOCTYPE html>
<html lang="en"><head><meta charset="utf-8"/><meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"/><title>HCI Application</title><link rel="apple-touch-icon" sizes="76x76" href="{{url_for('static', filename='img/favicon.ico')}}"><link rel="icon" type="image/png" href="{{url_for('static', filename='img/favicon.ico')}}"><meta content='width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0, shrink-to-fit=no' name='viewport'/><!-- Font Awesome Icons --><link rel="stylesheet" href="{{url_for('static', filename='fontawesome/css/all.css')}}"><!-- Main CSS --><link rel="stylesheet" href="{{url_for('static', filename='css/main.css')}}"/><!-- Animation CSS --><link rel="stylesheet" href="{{url_for('static', filename='css/vendor/aos.css')}}"/></head><body> <!---------- NAVBAR ----------><nav class="navbar navbar-expand-lg navbar-dark bg-purple fixed-top"><div class="container-fluid"><a class="navbar-brand" href="#"><i class="fas fa-robot mr-2"></i><strong>HCI</strong> Application</a><div class="navbar-collapse collapse" id="navbarColor02"><ul class="navbar-nav ml-auto d-flex align-items-center"><li class="nav-item"><input type="hidden" id="running_state" value="0"><button type="button" class="btn btn-block btn-primary btn-round mb-1"id="btn_running_state"onclick="run_serivce()"><i class="fas fa-play" id="i_running_state_icon"></i><b id="b_running_state_text">启动服务</b></button></li></ul></div></div></nav><!-- End Navbar --><main class="container-fluid"><div class="position-relative"><div class="container-fluid text-dark mt-5 pt-5"><!-- table --><table class="table table-left table-hover" id="tbl_log"><thead class="bg-primary text-white"><tr align="left"><th scope="col" style="width:120px;">#</th><th scope="col" style="width:300px;">Time</th><th scope="col">消息内容</th></tr></thead><tbody><tr align="center" class="text-black"><th scope="row" colspan="3">等待启动 ...</th></tr></tbody></table></div></div></main><!------------ JAVASCRIPTS ----------------> <script src="{{url_for('static', filename='js/vendor/jquery.min.js')}}" type="text/javascript"></script><script src="{{url_for('static', filename='js/vendor/popper.min.js')}}" type="text/javascript"></script><script src="{{url_for('static', filename='js/vendor/bootstrap.min.js')}}" type="text/javascript"></script><script src="{{url_for('static', filename='js/vendor/share.js')}}" type="text/javascript"></script><script src="{{url_for('static', filename='js/functions.js')}}" type="text/javascript"></script><script src="{{url_for('static', filename='js/vendor/aos.js')}}" type="text/javascript"></script><script src="{{url_for('static', filename='js/socket.io.js')}}" type="text/javascript"></script><noscript><style>*[data-aos] {display: block !important;opacity: 1 !important;visibility: visible !important;}</style></noscript><script>AOS.init({duration: 700,disable: function () {var maxWidth = 1200;return window.innerWidth < maxWidth;}});/*开启服务,获取分类运行结果*/var line_number = 1;var socket = io();// 专门接收后端推送消息socket.on('service_msg', function(data) {var row = "<tr>" +"<th scope=\"row\">" + line_number + "</th>" +"<td align=\"left\">" + data.time + "</td>" +"<td align=\"left\">" + data.msg + "</td>" +"</tr>"; line_number++;//添加数据到 table 第一行$("#tbl_log tbody").prepend(row);});/*运行服务,开始接收推送消息*/function run_serivce() {$("#btn_running_state").attr("onclick", "pause_service()");$("#i_running_state_icon").attr("class", "fas fa-pause");$("#b_running_state_text").html("暂停服务");var row = "<tr align=\"center\" class=\"text-success\"><th scope=\"row\" colspan=\"3\">启动成功,开始接收数据 ...</th></tr>"$("#tbl_log tbody").prepend(row);$.ajax({type: "get", // 请求方式url: "start_service", // 请求路径async: true, // 异步请求dataType: "json", // 预期返回一个 json 类型数据success: function (data) { // data是形参名,代表返回的数据console.log(data);}});}/*暂停服务*/function pause_service() {$("#btn_running_state").attr("onclick", "run_serivce()");$("#i_running_state_icon").attr("class", "fas fa-play");$("#b_running_state_text").html("启动服务");var row = "<tr align=\"center\" class=\"text-secondary\"><th scope=\"row\" colspan=\"3\">服务暂停,等待开启 ...</th></tr>"$("#tbl_log tbody").prepend(row);$.ajax({type: "get", // 请求方式url: "stop_service", // 请求路径async: true, // 异步请求dataType: "json", // 预期返回一个 json 类型数据success: function (data) { // data是形参名,代表返回的数据console.log(data);}});}</script></body>
</html>
运行步骤
cmd 或者 linux控制台运行即可
python app.py
此时能看到如下图所示
此时访问http://0.0.0.0:5200(0.0.0.0 替换成对应IP或者127.0.0.1或localhost即可看到图1-3效果)
代码理解
在python代码中,首先通过SocketIO封装flask app
socketio = SocketIO(app, cors_allowed_origins="*")
通过cors_allowed_origins="*"
来指定支持跨域访问限制问题
另外设定全局变量service_state = 0
用来控制服务运行状态,从而根据结果是否要向前端发送数据。
最后就是在启动接口/start_service
上增加状态判断死循环,只要service_state = 0
,就会不断向前端发送数据(我这加了2秒间歇),具体方法调用前面定义的socketio
变量的emit
函数即可,如下所示:
socketio.emit("service_msg", json_data)
而要停止推送服务的话,那只需要调用/stop_service
改变全局变量service_state
的值即可。
代码下载
【GitCode地址:flask_socketio_quickstart】