使用Flask-SocketIO完成服务端和客户端的双向通信

本文介绍如何使用Flask-SocketIO模块在Flask应用中实现客户端与服务器间的低延迟双向通信,包括安装配置、基本用法及通过WebSocket推送数据到前端的示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

**介绍:**flask-socketio模块实际上是封装了flask对websocket的支持,websocket在连接建立阶段是通过HTTP的握手方式进行的,这可以看做是为了兼容浏览器或者使用一些现成的功能来实现,这样一种捷径。当连接建立之后,客户端和服务端之间就不再进行HTTP通信了,所有信息交互都由websocket接管。Flask-SocketIO使Flask应用程序可以访问客户端和服务器之间的低延迟双向通信,使客户端建立与服务器的永久连接。

**适用的场景:**后台产生新的数据,需要在前台页面马上展示出来,例如数据监控、统计图实时变化更新等。

当然,我们可以使用ajax来完成,通过ajax使得前台定时去后台索要数据,但如果消息频繁,ajax需要不断的建立和释放连接,效果明显不如后端直接推送数据到前台更加合适。

Flask-SocketIO的使用

首先安装依赖:

pip install flask-socketio

一个简单的示例(对Flask代码加了一层包装):

from flask import Flask, render_template



from flask_socketio import SocketIO



 



app = Flask(__name__)



app.config['SECRET_KEY'] = 'secret!'



socketio = SocketIO(app)



 



if __name__ == '__main__':



socketio.run(app)

SocketIO发送消息

SocketIO可以使用send()和emit()函数向连接的客户端发送消息,两个函数有些区别,send()用于发送未命名事件消息,而emit()用于发送已命名事件消息。

实例代码:

@socketio.on('message')



def handle_message(message):



     send(message, namespace='/chat')



 



@socketio.on('my event')



def handle_my_custom_event(json):



      emit('my response', json, namespace='/chat')

namespace表示传入消息的命名空间,前台可以对应这个命名空间选择接收消息,如:

$(document).ready(function() {



        namespace = '/test';



        var socket = io.connect(location.protocol



    + '//' + document.domain + ':'



    + location.port + namespace);



 



        socket.on('server_response', function(res) {



            //res表示接收的数据,这里做数据的处理



        });



 



    });

一个简单使用SocketIO的完整实例

**功能:**后台五秒随机产生十个数字,在前台模版中动态刷新显示

后台代码:

#encoding:utf-8



#!/usr/bin/env python



from flask import Flask, render_template



from flask_socketio import SocketIO



import random



async_mode = None



app = Flask(__name__)



app.config['SECRET_KEY'] = 'secret!'



socketio = SocketIO(app)



 



@app.route('/')



def index():



    return render_template('test.html')



 



@socketio.on('connect', namespace='/test_conn')



def test_connect():



    while True:



        socketio.sleep(5)



        t = random_int_list(1, 100, 10)



        socketio.emit('server_response',



                      {'data': t},



                      namespace='/test_conn')



 



def random_int_list(start, stop, length):



    start, stop = (int(start), int(stop)) if start <= stop else (int(stop), int(start))



    length = int(abs(length)) if length else 0



    random_list = []



    for i in range(length):



        random_list.append(random.randint(start, stop))



    return random_list



 



if __name__ == '__main__':



    socketio.run(app, debug=True)

页面模版:

<!DOCTYPE html>



<html lang="en">



<head>



    <meta charset="UTF-8">



    <title></title>



    <script type="text/javascript" src="//cdn.bootcss.com/jquery/3.1.1/jquery.min.js"></script>



    <script type="text/javascript" src="//cdn.bootcss.com/socket.io/1.5.1/socket.io.min.js"></script>



</head>



<body>



<h2 id="t"></h2>



<script type="text/javascript">



    $(document).ready(function() {



        namespace = '/test_conn';



        var socket = io.connect(location.protocol + '//' + document.domain + ':' + location.port + namespace);



        socket.on('server_response', function(res) {



            var t = res.data;



            $("#t").text(t);



        });



 



    });



</script>



</body>



</html>

最后,我们使用SocketIO结合Echarts实现一个简单的实时监控图

效果如图所示:

img

后台代码:

#encoding:utf-8



#!/usr/bin/env python



import psutil



import time



from threading import Lock



from flask import Flask, render_template



from flask_socketio import SocketIO



 



async_mode = None



app = Flask(__name__)



app.config['SECRET_KEY'] = 'secret!'



socketio = SocketIO(app, async_mode=async_mode)



thread = None



thread_lock = Lock()



 



# 后台线程 产生数据,即刻推送至前端



def background_thread():



    count = 0



    while True:



        socketio.sleep(5)



        count += 1



        t = time.strftime('%M:%S', time.localtime())



        # 获取系统时间(只取分:秒)



        cpus = psutil.cpu_percent(interval=None, percpu=True)



        # 获取系统cpu使用率 non-blocking



        socketio.emit('server_response',



                      {'data': [t, cpus], 'count': count},



                      namespace='/test')



        # 注意:这里不需要客户端连接的上下文,默认 broadcast = True



 



 



@app.route('/')



def index():



    return render_template('index.html', async_mode=socketio.async_mode)



 



@socketio.on('connect', namespace='/test')



def test_connect():



    global thread



    with thread_lock:



        if thread is None:



            thread = socketio.start_background_task(target=background_thread)



 



if __name__ == '__main__':



    socketio.run(app, debug=True)

页面模版:

<!DOCTYPE html>



<html lang="en">



<head>



    <meta charset="utf-8">



    <title>系统监控走势图</title>



    <script type="text/javascript" src="//cdn.bootcss.com/jquery/3.1.1/jquery.min.js"></script>



    <script type="text/javascript" src="//cdn.bootcss.com/socket.io/1.5.1/socket.io.min.js"></script>



    <!-- ECharts 3 引入 -->



    <script src="http://echarts.baidu.com/dist/echarts.min.js"></script>



</head>



 



<body>



    <div id="main" style="height:500px;border:1px solid #ccc;padding:10px;"></div>



 



    <script type="text/javascript">



 



    var myChart = echarts.init(document.getElementById('main'));



 



    myChart.setOption({



        title: {



            text: '系统监控走势图'



        },



        tooltip: {},



        legend: {



            data:['cpu']



        },



        xAxis: {



            data: []



        },



        yAxis: {},



        series: [{



            name: 'cpu',



            type: 'line',



            data: []



        }]



    });



 



 



    var time = ["","","","","","","","","",""],



        cpu = [0,0,0,0,0,0,0,0,0,0]



 



 



    //准备好统一的 callback 函数



    var update_mychart = function (res) {



    //res是json格式的response对象



 



        // 隐藏加载动画



        myChart.hideLoading();



 



        // 准备数据



        time.push(res.data[0]);



        cpu.push(parseFloat(res.data[1]));



        if (time.length >= 10){



            time.shift();



            cpu.shift();



        }



 



        // 填入数据



        myChart.setOption({



            xAxis: {



                data: time



            },



            series: [{



                name: 'cpu', // 根据名字对应到相应的系列



                data: cpu



            }]



        });



 



    };



 



    // 首次显示加载动画



    myChart.showLoading();



 



 



    // 建立socket连接,等待服务器“推送”数据,用回调函数更新图表



    $(document).ready(function() {



        namespace = '/test';



        var socket = io.connect(location.protocol + '//' + document.domain + ':' + location.port + namespace);



 



        socket.on('server_response', function(res) {



            update_mychart(res);



        });



 



    });



 



    </script>



</body>



</html>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值