Python web学习笔记——(一)flask实现websocket+Echarts图表数据实时更新

flaskio+echarts实现图表实时更新

  • 项目概述
  • 遇到的问题
    • Websocket 概述
    • 使用WebSocket协议的原因
    • Flask实现WebSocket(全双工通信)
      • 方法一、使用flask-sockets(经过测试,无法连接)
      • 方法二、通过 `flask-sockeio` 实现全双工通信(可用)
  • JAVA移植至Python
    • 项目结构
    • 自定义工具包
    • HTML/JS文件
    • Python `Flask-socketio`后台

项目概述

本人毕业设计是一个基于WSN的环境监控系统,实现流程如下:
硬件端采集数据(包括温湿度,光照强度,当前位置经纬度等),并通过WiFi模块,上传至后端,后端采用JAVA编写,后端接收数据并对其进行存储,同时转发至客户端(Android,Web端
具体流程图如下:
Python web学习笔记——(一)flask实现websocket+Echarts图表数据实时更新_第1张图片
由于最近在看Flask,所以打算吧JAVA后端这部分移植到Flask上面

遇到的问题

在移植过程中遇到的最大的坑,普通的Flask不支持Websocket

我在JAVA里面,使用的是Tomcat进行部署,他是支持Websocket的,但是在Flask中是不支持的。

Websocket 概述

WebSocket是HTML5的一个协议,他与HTTP协议有交集,但不是全部。
Python web学习笔记——(一)flask实现websocket+Echarts图表数据实时更新_第2张图片
1.首先,相对于HTTP这种非持久的协议来说,Websocket是一个持久化的协议。

一般来讲,HTTP协议就是一个 Request 和一个 Response ,由客户端发起Request ,服务器返回Response ,完成请求后就会断开。
在HTTP1.1中进行了改进,使得有一个keep-alive,也就是说,在一个HTTP连接中,可以发送多个Request,接收多个Response。 在HTTP中永远一个request只能有一个response。而且这个response也是被动的,不能主动发起。

而对于WebSocket,他是一种长连接的,全双工通信协议,即在建立连接后,保持长连接,服务端可以主动向客户端发送数据,客户端也可以主动向服务端发数据,是一个双向过程。

2.WebSocket是基于HTTP协议的,或者说借用了HTTP协议来完成一部分握手

GET /chat HTTP/1.1
Host: server.example.com
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw==
Sec-WebSocket-Protocol: chat, superchat
Sec-WebSocket-Version: 13
Origin: http://example.com

其中和两个关键字,就是告诉服务器,发起的是websocket协议。

Upgrade: websocket
Connection: Upgrade

这个key就相当于验证的作用

Sec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw==

这个就相当于客户端主动与服务端建立WebSocket请求。(通过HTTP的方式建立)

接下来消息收发就按照WebSocket自身独特的协议部分进行处理

使用WebSocket协议的原因

在我的功能需求中,当有新的数据上传至服务器时,需要在客户端(Android,Web)中及时地动态显示,保证数据的实时性。

传统的方法是:使用HTTP,客户端每隔一段时间向服务器进行轮询,是否有新数据到来。

该方法,每隔一段时间就要进行轮询,并且数据的时效性也不能保证,若时间间隔设置得短,那么资源消耗就比较大,若时间间隔设置过长,时效性就差

使用WebSocket,客户端上线后(与服务端建立了WebSocketl连接),与服务端保持长连接,当服务端有新数据到来时,就将数据转发至客户端,客户端(Android、Web)即能及时收到更新的数据。

Flask实现WebSocket(全双工通信)

经过查阅资料,Flask可以使用2种方式实现,WebSocket

方法一、使用flask-sockets(经过测试,无法连接)

安装flask-sockets

pip install flask-sockets

服务端

from flask import Flask
from flask_sockets import Sockets

import datetime
import time


app = Flask(__name__)
sockets = Sockets(app)

@sockets.route('/websocket')
def echo_socket(ws):
    while not ws.closed:
        now = datetime.datetime.now().isoformat() + 'Z'
        ws.send(now)  #发送数据

@app.route('/')
def hello():
    return 'Hello World!'
if __name__ == "__main__":
    from gevent import pywsgi
    from geventwebsocket.handler import WebSocketHandler
    server = pywsgi.WSGIServer(('', 5000), app, handler_class=WebSocketHandler)
    print('server start')
    server.serve_forever()

Web端


<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Titletitle>
    <script src="https://cdn.bootcss.com/jquery/3.2.0/jquery.js">script>
head>
<body>
    <div id="time" style="width: 300px;height: 50px;background-color: #0C0C0C;
    color: white;text-align: center;line-height: 50px;margin-left: 40%;font-size: 20px">div>

    <script>
            var ws = new WebSocket("ws://127.0.0.1:5000/websocket");  #连接server

            ws.onmessage = function (event) {
      
                content = document.createTextNode(event.data); # 接收数据
                $("#time").html(content);

            };

    script>
    body>
html>

flask-sockets的另一种实现方式(测试无法连接)
服务端

from flask import Flask,request
from geventwebsocket.websocket import WebSocket  # 导入这个其实没用,只是用来在敲代码的时候能有提示。
from gevent.pywsgi import WSGIServer
from geventwebsocket.handler import WebSocketHandler

app = Flask(__name__)

@app.route('/ws')
def ws():   
	print(request.environ.get('wsgi.websocket'))
	print(request.environ)
    user_socket = request.environ.get('wsgi.websocket') # type: WebSocket
    while 1:
        msg = user_socket.receive() # 接受消息
        print(msg)
        user_socket.send(msg)  # 发送消息

if __name__ == '__main__':
    http_serv = WSGIServer(('0.0.0.0',9527),app,handler_class=WebSocketHandler)
    http_serv.serve_forever()

客户端(Web)


<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Titletitle>
head>
<body>
<script type="text/javascript">
    var ws = new WebSocket('ws://127.0.0.1:9527/ws');
    ws.onmessage = function (data) {
      
        alert(data)
    }
script>
body>
html>

通过flask-socket实现Websocket,试了很多次都没用,可能是用的包比较新,找的教程都是很久比较老的

方法二、通过 flask-sockeio 实现全双工通信(可用)

安装flask-socketio
pip install flask-socketio

socketio 是一种以广播的形式,发布和订阅消息

服务端

import json
from flask import Flask, render_template, request, redirect, sessions
from flask_socketio import SocketIO, emit #导入socketio包

name_space = '/websocket'
app = Flask(__name__)
app.secret_key = 'jzw'
socketio = SocketIO(app)
client_query = []

@socketio.on('connect', namespace=name_space)# 有客户端连接会触发该函数
def on_connect():
    # 建立连接 sid:连接对象ID
    client_id = request.sid
    client_query.append(client_id)
    # emit(event_name, broadcasted_data, broadcast=False, namespace=name_space, room=client_id)  #指定一个客户端发送消息
    # emit(event_name, broadcasted_data, broadcast=True, namespace=name_space)  #对name_space下的所有客户端发送消息
    print('有新连接,id=%s接加入, 当前连接数%d' % (client_id, len(client_query)))

@socketio.on('disconnect', namespace=name_space)# 有客户端断开WebSocket会触发该函数
def on_disconnect():
    # 连接对象关闭 删除对象ID
    client_query.remove(request.sid)
    print('有连接,id=%s接退出, 当前连接数%d' % (request.sid, len(client_query)))

# on('消息订阅对象', '命名空间区分')
@socketio.on('message', namespace=name_space)
def on_message(message):
    """ 服务端接收消息 """
    print('从id=%s客户端中收到消息,内容如下:' % request.sid)
    print(message)
    emit('my_response_message', "我收到了你的信息", broadcast=False, namespace=name_space, room=client_id)  #指定一个客户端发送消息
    # emit('my_response_message', broadcasted_data, broadcast=True, namespace=name_space)  #对name_space下的所有客户端发送消息
    
@app.route('/') #初始化页面
def a():
   return render_template("test.html")
 
if __name__ == '__main__':
    socketio.run(app, host='0.0.0.0', port=5000, debug=False)
    # app.run()

开启服务后
Python web学习笔记——(一)flask实现websocket+Echarts图表数据实时更新_第3张图片

客户端
前提,需添加标签导入socket.io.js

<script type="text/javascript" src="https://cdn.bootcdn.net/ajax/libs/socket.io/2.3.0/socket.io.js">script>

<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Titletitle>
    <script type="text/javascript" src="https://cdn.bootcdn.net/ajax/libs/socket.io/2.3.0/socket.io.js">script>
head>
<body>

 <div><button onclick="ws()">连接服务端button>div>
 <div><button onclick="clos_con()">断开连接button>div>
 <div><button onclick="send_msg()">发送消息给服务端button>div>
<script type="text/javascript">
    windw_socket=null
    function ws(){
      
	namespace = '/websocket';
	var websocket_url = location.protocol+'//' + document.domain + ':' + location.port + namespace;
	var socket=io.connect(websocket_url);
	// socket.emit('connect2', {'param':'value'});	//发送消息
	// socket.close()
	socket.on('connect',function(data){
      
		console.log('connecte:'+data);
		alert("建立连接成功")
		windw_socket=socket
	});
	socket.on('disconnect',function(data){
      
		alert("连接已断开")
		console.log('disconnecte:'+data);
	});

	socket.on('my_response_message',function(data){
      
		console.log('my_response_message:'+data);
		alert("收到服务端的回复:"+data)
	});
}
    function clos_con(){
      
	    if(windw_socket!=null){
      
	        windw_socket.close()
        }
    }
    window.onbeforeunload= function(event) {
      
	if (windw_socket!=null && !windw_socket.closed){
      
		// confirm(windw_socket.closed)
		windw_socket.close()
	}
    }
    window.onunload= function(event) {
      
	if (windw_socket!=null && !windw_socket.closed){
      
		//confirm(windw_socket.closed)
		windw_socket.close()
	}
    }
    function send_msg(){
      
	    if(windw_socket!=null){
      
	        windw_socket.emit('message', "这里是客户端");
        }
    }
script>
body>
html>

三个按钮
Python web学习笔记——(一)flask实现websocket+Echarts图表数据实时更新_第4张图片
点击‘连接服务端’
在这里插入图片描述
在这里插入图片描述
(测试连接成功)

点击发送消息给服务端
在这里插入图片描述
在这里插入图片描述
(消息测试成功)

断开连接
在这里插入图片描述
综上已完成flask-socketio的测试
成功实现全双工通信。

JAVA移植至Python

项目结构

Python web学习笔记——(一)flask实现websocket+Echarts图表数据实时更新_第5张图片

自定义工具包

parse_local 是自定义解析经纬度的包,使用百度地图API

import requests
import json

AK = "私人AK,通过百度地图官方注册获取";
URL = "http://api.map.baidu.com/reverse_geocoding/v3/?ak=" + AK + "&output=json&coordtype=wgs84ll&location=";

class Location(object):
    def __init__(self, formatted_address, country=None, province=None, city=None, district=None, street=None):
        self.formatted_address = formatted_address
        self.country = country
        self.province = province
        self.city = city
        self.district = district
        self.street = street

def get_addr(local):
    url_full=URL+local
    re = json.loads(requests.get(url_full).text)
    if re["status"] == 0:
        result = re["result"]
        address_component = result["addressComponent"]
        stree = address_component["district"] + address_component["town"] + \
                address_component["street"] + address_component["street_number"]
        return Location(formatted_address=result["formatted_address"], country=address_component["country"],
                 province=address_component["province"], city=address_component["city"],street=stree)
    return "no_addr"

sql_manger 是 自定义的数据库操作包,用于数据库的数据存取,以及类封装

import pymysql
import datetime
import traceback

con_options = {
     'host': '数据库ip', 
               'port': 3306,
               'user': '用户名',
               'password': '密码',
               'database': '数据库名称',
               'charset': 'utf8'}


class DataManger(object):
    def _connect(self):  #单下划线-保护类型方法,打开数据库连接
        try:
            conn = pymysql.connect(host=con_options['host'], port=con_options['port'],
                                   user=con_options['user'], password=con_options['password'],
                                   database=con_options['database'], charset=con_options['charset'])
            cursor = conn.cursor(cursor=pymysql.cursors.DictCursor)
        except Exception:
            print("连接数据库失败")
            conn.close()
            traceback.print_exc()
            return None
        return conn, cursor

    def _closeAll(self, conn, cursor):
        try:
            conn.close()
            cursor.close()
            print('关闭数据库连接成功')
        except Exception:
            traceback.print_exc()
            print('关闭数据库连接失败')

    def _executeAltSql(self, conn, cursor, sql_str, values):#SQL修改/删除语句,不需要返回结果
        try:
            cursor.execute(sql_str, values)
            conn.commit()
            return True
        except Exception:
            print("执行修改失败")
            traceback.print_exc()
        finally:
            self._closeAll(conn, cursor)

    def _executeSerchSql(self, conn, cursor, sql_str, values):#SQL查询语句,需返回结果
        try:
            cursor.execute(sql_str, values)
            values = cursor.fetchall()
            return values
        except Exception:
            print("执行查询失败")
            traceback.print_exc()
        finally:
            self._closeAll(conn, cursor)


class UserHead(DataManger):
    def __init__(self, user_id, user_name="none", user_password="123"):
        super().__init__()
        self._user_id = user_id
        self._user_name = user_name
        self._user_password = user_password

    @property
    def user_id(self):
        return self._user_id

    @property
    def user_name(self):
        return self._user_name

    @property
    def user_password(self):
        return self._user_password

    def serch_user(self):
        conn, cursor = self._connect()
        sql = 'select * from users where user_id = %s'
        return self._executeSerchSql(conn, cursor, sql, self._user_id)

    def insert_user(self):
        conn, cursor = self._connect()
        sql = 'insert into users (user_id,user_name,user_passwd,create_date) values ' \
              '(%s,%s,%s,%s)'
        return self._executeAltSql(conn, cursor, sql,
                                   (self._user_id, self._user_name, self._user_password, datetime.datetime.now()))

    def del_user(self):
        conn, cursor = self._connect()
        sql = "DELETE FROM `users` WHERE user_id=%s"
        return self._executeAltSql(conn, cursor, sql, self._user_id)

    def is_in_db(self):
        return len(self.serch_user()) > 0


class UserData(UserHead):
    def __init__(self, user_head, localtion="未指定", temperature=None, humidity=None, co_2=None, o_2=None, ch_4=None, light=None):
        super().__init__(user_head.user_id, user_head.user_name, user_head.user_password)
        self._localtion = localtion
        self._temperature = temperature
        self._humidity = humidity
        self._co_2 = co_2
        self._o_2 = o_2
        self._ch_4 = ch_4
        self._light = light


    def serch_data_least_n(self, n=1):
        conn, cursor = self._connect()
        sql = 'select * from data where user_id = %s order by data_time desc limit %s'
        data_result_list = self._executeSerchSql(conn, cursor, sql, (self._user_id, n))
        for data_obj in data_result_list:
            data_obj['data_time'] = data_obj['data_time'].strftime('%Y-%m-%d %H:%M:%S')
        return data_result_list

    def inser_data(self):
        if not self.is_in_db():
            print("用户不存存在,自动注册")
            self.insert_user()
        conn, cursor = self._connect()
        sql = 'insert into data (user_id,user_name,data_time,localtion,temperature,humidity,CO2_con,O2_con,CH4_CON,Light_Inte) values ' \
                  '(%s,%s,%s,%s,%s,%s,%s,%s,%s,%s)'
        return self._executeAltSql(conn, cursor, sql,
                                   (self._user_id, self._user_name, datetime.datetime.now(), self._localtion,
                                    self._temperature, self._humidity, self._co_2, self._o_2, self._ch_4, self._light))

HTML/JS文件

HTML文件,导入所需要的包,图表使用开源框架Echarts


<html lang="en" style="height: 100%">
<head>
    
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.js" type="text/javascript" charset="utf-8">script>
    
    <script type="text/javascript" src="https://cdn.jsdelivr.net/npm/echarts/dist/echarts.min.js">script>
    <script type="text/javascript" src="https://cdn.jsdelivr.net/npm/echarts-gl/dist/echarts-gl.min.js">script>
    <script type="text/javascript" src="https://cdn.jsdelivr.net/npm/echarts-stat/dist/ecStat.min.js">script>
    <script type="text/javascript" src="https://cdn.jsdelivr.net/npm/echarts/dist/extension/dataTool.min.js">script>
    <script type="text/javascript" src="https://cdn.jsdelivr.net/npm/echarts/map/js/china.js">script>
    <script type="text/javascript" src="https://cdn.jsdelivr.net/npm/echarts/map/js/world.js">script>
    <script type="text/javascript" src="https://cdn.jsdelivr.net/npm/echarts/dist/extension/bmap.min.js">script>
    
    <script type="text/javascript" src="https://cdn.bootcdn.net/ajax/libs/socket.io/2.3.0/socket.io.js">script>
    <title>数据检测可视化title>
    <style>
	div{
      float:left}
    style>
head>
<body style="height: 100%; margin: 0">
	
	<div id="line" style="height:100%; Width:100%">div>
	
	<script src="{
      { url_for('static',filename='js/ajaxEcharts.js') }}" type="text/javascript" charset="utf-8">
	script>
body>
html>

JS文件

/* ajaxEcharts是自己编写 */

var windw_socket=null

//1.折线图可视化化
//2.折线样式设置(这里面的属性都是Echarts,可以根据自己想法从里面选取属性)
var option = {
     
	    title: {
     
	        text: '数据监测',
	        subtext: 'xxx'
	    },
	    tooltip: {
     
	        trigger: 'axis'
	    },
	    legend: {
     
	        data:['湿度','温度','光照强度','二氧化碳']
	    },
	    toolbox: {
     
	        show: true,
	        feature: {
     
	            dataZoom: {
     
	                yAxisIndex: 'none'
	            },
	            dataView: {
     readOnly: false},
	            magicType: {
     type: ['line','bar']},
	            restore: {
     },
	            saveAsImage: {
     }
	        }
	    },
	    xAxis: {
     
	        type: 'category',
	        boundaryGap: false,
	        data:[]
	    },
	    yAxis: {
     
	        type:'value',
	        axisLabel: {
     
	            formatter: '{value}'
	        }
	    },
	    series: [
	        {
     
	            name:'湿度',
	            type:'line',
	            data:[],
	            markPoint: {
     
	                data: [
	                    {
     type: 'max', name: '最高值'},
	                    {
     type: 'min', name: '最低值'}
	                ]
	            },
	            markLine: {
     
	                data: [
	                    {
     type: 'average', name:'平均值'}
	                ]
	            }
	        },
	        {
     
	            name:'温度',
	            type:'line',
	            data:[],
	            markPoint: {
     
	                data: [
	                    {
     type: 'max', name: '最高值'},
	                    {
     type: 'min', name: '最低值'}
	                ]
	            },
	            markLine: {
     
	                data: [
	                    {
     type: 'average', name:'平均值'}
	                ]
	            }
	        },{
     
	            name:'光照强度',
	            type:'line',
	            data:[],
	            markPoint: {
     
	                data: [
	                    {
     type: 'max', name: '最高值'},
	                    {
     type: 'min', name: '最低值'}
	                ]
	            },
	            markLine: {
     
	                data: [
	                    {
     type: 'average', name:'平均值'}
	                ]
	            }
	        },{
     
	            name:'二氧化碳',
	            type:'line',
	            data:[],
	            markPoint: {
     
	                data: [
	                    {
     type: 'max', name: '最高值'},
	                    {
     type: 'min', name: '最低值'}
	                ]
	            },
	            markLine: {
     
	                data: [
	                    {
     type: 'average', name:'平均值'}
	                ]
	            }
	        }
	    ]
	};

var myChart;
myChart = echarts.init(document.getElementById('line'));   //pie是jsp里面的div的id属性
//myChart.setOption(option);

 window.onload = function () {
     
 		intChar();
 		ws();
        }
var values=[]; 
function intChar(){
     
	myChart.showLoading();
	option.xAxis.data.length=0;
	for(var i=0;i<option.series.length;i++) 
		option.series[i].data.length=0;
	$.ajax({
     
	    type : "get",
	    async : false,            //异步请求(同步请求将会锁住浏览器,用户其他操作必须等待请求完成才可以执行)
	    url : "/get_data?count_n=10&product_id=001",//请求发送到url处
	    // data : {Cont:'10',product_id:'001'},
	    dataType :"json",        //返回数据形式为json
	    success: function(result) {
     
	        //请求成功时执行该函数内容,result即为服务器返回的json对象
	    	var re=result.DataObj;
	    	var len=re.length;
			for(var i=len-1;i>=0;i--){
     
				var data=re[i];
				var dateTime=new Date(data.data_time).toLocaleTimeString();
					option.xAxis.data.push(dateTime);
					option.series[0].data.push(data.humidity);
					option.series[1].data.push(data.temperature);
					option.series[2].data.push(data.Light_Inte);
					option.series[3].data.push(data.CH4_CON);
			}
			myChart.setOption(option);
			//隐藏加载动画略
			myChart.hideLoading();
	    },
	    error : function(errorMsg) {
     
	        //请求失败时执行该函数
	        alert("请求数据失败!");
	        myChart.hideLoading();
	    }
	});
}
function ws() {
     
	namespace = '/websocket';
	var websocket_url = location.protocol+'//' + document.domain + ':' + location.port + namespace;
	var socket=io.connect(websocket_url);
	// socket.emit('connect2', {'param':'value'});	//发送消息
	// socket.close()
	socket.on('connect',function(data){
     
		console.log('connecte:'+data);
		windw_socket=socket
	});
	socket.on('disconnect',function(data){
     
		console.log('disconnecte:'+data);
	});

	socket.on('response',function(data){
     
		console.log('response:'+data);
	});
	socket.on('updateView',function(data){
     

		console.log('message:'+data);
		parse_data(data)
	});

}
function parse_data(data) {
     
	 var axisData=(new Date()).toLocaleTimeString();
	 var mdata=JSON.parse(data).DataObj;
	 if(option.xAxis.data.length<10){
     
	 	option.xAxis.data.push(axisData);
	 	option.series[0].data.push(mdata.Humi);
	 	option.series[1].data.push(mdata.Temp);
	 	option.series[2].data.push(mdata.Light);
	 	option.series[3].data.push(mdata.CH4);
	 }else {
     
	 	option.xAxis.data.shift();
	 	option.series[0].data.shift();
	 	option.series[1].data.shift();
	 	option.series[2].data.shift();
	 	option.series[3].data.shift();
	 	option.xAxis.data.push(axisData);
	 	option.series[0].data.push(mdata.Humi);
	 	option.series[1].data.push(mdata.Temp);
	 	option.series[2].data.push(mdata.Light);
	 	option.series[3].data.push(mdata.CH4);
	   }
	   myChart.setOption(option);
}
window.onbeforeunload= function(event) {
     
	if (windw_socket!=null && !windw_socket.closed){
     
		// confirm(windw_socket.closed)
		windw_socket.close()
	}
}
window.onunload= function(event) {
     
	if (windw_socket!=null && !windw_socket.closed){
     
		//confirm(windw_socket.closed)
		windw_socket.close()
	}
}

// window.onunload = function(event) {
     
// 	return confirm("确定离开此页面吗?");
// }
 

Python Flask-socketio后台

import json
from flask import Flask, render_template, request, redirect, sessions
from flask_socketio import SocketIO, emit
from py_src.utils import sql_manger
from py_src.utils import parse_local

name_space = '/websocket'
app = Flask(__name__)
app.secret_key = 'jiangzhiwei'
socketio = SocketIO(app)
client_query = []


@app.route('/')
def index():
    return redirect('/dataView')


@app.route('/login', methods=['GET', 'POST'])#还未写html
def login():
    if request.method == 'GET':
        return render_template('login.html')


@app.route('/dataView', methods=['GET', 'POST'])  # 添加路由的第一种方式
def data_view():
    if request.method == 'GET':
        return render_template('dataView.html')

    if request.method == 'POST':
        json_str = request.get_data(as_text=True)
        json_object = json.loads(json_str)
        user_name = json_object["USER_NAME"]
        user_id = json_object["USER_ID"]
        data_obj = json_object["DataObj"]
        location = parse_local.get_addr(data_obj["Loca"]).formatted_address
        user_head = sql_manger.UserHead(user_id=user_id, user_name=user_name)
        user_data = sql_manger.UserData(user_head=user_head, localtion=location,
                                        temperature=data_obj["Temp"], humidity=data_obj["Humi"], ch_4=data_obj["CH4"],
                                        light=data_obj["Light"])
        print(json_str)
        if user_data.inser_data():
            emit('updateView', json_str, broadcast=True, namespace=name_space)
        return ""


@app.route('/get_data', methods=['GET'])  # 添加路由的第一种方式
def get_data():
    if request.method == 'GET':
        count_n = int(request.args.get("count_n"))
        product_id = request.args.get("product_id")
        head = sql_manger.UserHead(product_id)
        data = sql_manger.UserData(head)
        data_result_list = data.serch_data_least_n(count_n)
        re_dict = {
     }
        re_dict["DataObj"] = data_result_list
        print(re_dict)
        return re_dict


# on('消息订阅对象', '命名空间区分')
@socketio.on('message', namespace=name_space)
def on_message(message):
    """ 服务端接收消息 """
    print('从id=%s客户端中收到消息,内容如下:' % request.sid)
    print(message)


@socketio.on('connect', namespace=name_space)
def on_connect():
    # 建立连接 sid:连接对象ID
    client_id = request.sid
    client_query.append(client_id)
    # emit(event_name, broadcasted_data, broadcast=False, namespace=name_space, room=client_query[0])  #指定一个客户端发送消息
    print('有新连接,id=%s接加入, 当前连接数%d' % (client_id, len(client_query)))


@socketio.on('disconnect', namespace=name_space)
def on_disconnect():
    # 连接对象关闭 删除对象ID
    client_query.remove(request.sid)
    print('有连接,id=%s接退出, 当前连接数%d' % (request.sid, len(client_query)))


if __name__ == '__main__':
    socketio.run(app, host='0.0.0.0', port=5000, debug=False)
    # app.run()

你可能感兴趣的:(Web开发笔记,python,flask)