使用flask_socketio实现服务端向客户端定时推送
websocket连接是客户端与服务器之间永久的双向通信通道,直到某方断开连接。
双向通道意味着在连接时,服务端随时可以发送消息给客户端,反之亦然,这在一些需要即时通讯的场景比如多人聊天室非常重要。
flask_socketio实现了对websocket的封装,它可以让运行flask应用的服务端和客户端建立全双工通道。
flask_socketio是一个python库,是flask框架的扩展。
一、安装
pip install flask-socketio
二、实现对flask的封装
from flask import Flask, render_template
from flask_socketio import SocketIO,emit
app = Flask(__name__)
app.config['SECRET_KEY'] = 'secret!'
socketio = SocketIO(app) if __name__ == '__main__':
socketio.run(app, debug=True)
socketio.run()函数封装了flask的web服务器的启动
三、服务端向客户端推送
socketio的两个函数send()和emit()都可以实现消息发送,前者用于无名事件,后者用于命名的事件。
事件是消息的名称。如果把消息比做信件,事件就是贴在信封上的标识,这个标识规定了信件送往客户端或服务端的某个函数。
from flask import Flask, render_template
from flask_socketio import SocketIO,emit
app = Flask(__name__)
app.config['SECRET_KEY'] = 'secret!'
socketio = SocketIO(app) @socketio.on('connect', namespace='/test_conn')
def test_connect():
socketio.emit('server_response',
{'data': ‘connected’},namespace='/test_conn') if __name__ == '__main__':
socketio.run(app, debug=True)
比如上面socketio.on('connect',namespace='/test_conn')中的connect就是soketio的内置事件,当客户端与服务端连接之后,前端和后端都会收到一个名为‘connect’的事件,服务端接到这个事件就会执行test_connect函数中的内容了。
再说namespace,namespace可以标志多个事件,在官方文档的解释是“Namespaces allow a client to open multiple connections to the server that are multiplexed on a single socket.”。当一个客户端连接服务器的不同命名域的时候,可以在同一个socket连接里完成。我的理解是一个namespace就定义了一个后端websocket连接的接口,客户端与服务器通过三次握手建立socket连接后,连接不同的服务器接口,socket的连接并不会断开。这可以类比于http的路由(但是完全不同哦,因为传输协议完全不一样),在http连接范畴,当用户登录后,访问服务器不同的路由并不会改变它的登录状态。一个后端接口可以接受多个客户端的socket连接,如果在后端的emit中定义‘broadcast=True’,那么所有连接到这个命名域的客户端都会收到这个消息,命名域之间也可以通过发送消息指定命名域的方式来相互通信。
再看soketio.emit,第一个参数'server_response'是服务端发送这个消息的事件名,在客户端要建立一个接受这个事件的函数处理,后面的字典就是消息内容,namespace='/test_conn'表示这个消息还是发送到同一个信道(test_conn)中。emit发送信息只能从前端发到后端或者从后端发向前端,如果在在前端emit(‘event’,{data})再写socket.on('event', {data})是收不到的。
四、定时推送
实验的目的是服务端定时发送一个随机数到客户端,并且客户端可以及时显示。
一开始,我在socketio装饰的函数中写了一个while循环
from flask import Flask, render_template
from flask_socketio import SocketIO,emit
import random
async_mode = None
app = Flask(__name__)
app.config['SECRET_KEY'] = 'secret!'
socketio = SocketIO(app) @app.route('/')
def index():
return render_template('index.html') @socketio.on('connect', namespace='/test_conn')
def test_connect():
while True:
socketio.sleep(5)
t = random.randint(1, 100)
socketio.emit('server_response',
{'data': t},namespace='/test_conn') if __name__ == '__main__':
socketio.run(app, debug=True)
事实证明这样是行不通的,虽然看上去,虽然服务端陷入while的死循环中,但是emit函数每次都会执行,所以理论上客户端应该可以定时收到服务端的随机数。但是结果是客户端根本接收不到,连soketio.on函数都没有触发运行。
原因应该是当服务端陷入死循环,会影响与客户端之间的websocket连接,总之写while true需谨慎
在flask_socketio的示例程序中,我找到了用后台线程进行while循环以解决这个问题的方法。
from flask import Flask, render_template
from flask_socketio import SocketIO,emit
from threading import Lock
import random
async_mode = None
app = Flask(__name__)
app.config['SECRET_KEY'] = 'secret!'
socketio = SocketIO(app)
thread = None
thread_lock = Lock() @app.route('/')
def index():
return render_template('index.html') @socketio.on('connect', namespace='/test_conn')
def test_connect():
global thread
with thread_lock:
if thread is None:
thread = socketio.start_background_task(target=background_thread) def background_thread():
while True:
socketio.sleep(5)
t = random.randint(1, 100)
socketio.emit('server_response',
{'data': t},namespace='/test_conn') if __name__ == '__main__':
socketio.run(app, debug=True)
五、客户端
index.html的内容如下
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
<script type="text/javascript" src="//code.jquery.com/jquery-1.4.2.min.js"></script>
<script type="text/javascript" src="//cdnjs.cloudflare.com/ajax/libs/socket.io/1.3.5/socket.io.min.js"></script>
</head>
<body>
<h1 id="t"></h1>
<script type="text/javascript">
$(document).ready(function() {
namespace = '/test_conn';
var socket = io.connect(location.protocol + '//' + document.domain + ':' + location.port + namespace, {transports: ['websocket']});
socket.on('server_response', function(res) {
console.log(res.data);
$('#t').text(res.data);
});
});
</script>
</body>
</html>
注意客户端也要导入socketio的库,然后用io.connect建立命名域的socket连接。
如果不加{transports: ['websocket']},实际上建立的是长轮询。长轮询或websocket都是由客户端发起的
最后在浏览器输入http://127.0.0.1:5000就可以了
六、结果

开发者工具的console可以查看日志

使用flask_socketio实现服务端向客户端定时推送的更多相关文章
- 利用控制台承载SignalR作为服务端、及第三方推送信息
一 首先建立一个控制台需要引用一些组件 特别要注意引用Microsoft.Owin.Host.HttpListener别忘了这个组件,不引用他可能程序正常运行不会报错,但服务器一直开启失败(我之前就是 ...
- java服务端集成极光消息推送--详细开发步骤
1.极光推送账号准备 要使用极光消息推送必须先在官方网站上注册账号,并添加应用. 产品介绍:https://docs.jiguang.cn/jpush/guideline/intro/ 注册开发者账号 ...
- php做推送服务端实现ios消息推送
本文部分内容引用于 http://zxs19861202.iteye.com/blog/1532460 准备工作 1.获取手机注册应用的deviceToken(iphone手机注册应用时返回唯一值de ...
- oauth2.0服务端与客户端搭建
oauth2.0服务端与客户端搭建 - 推酷 今天搭建了oauth2.0服务端与客户端.把搭建的过程记录一下.具体实现的功能是:client.ruanwenwu.cn的用户能够通过 server.ru ...
- 解决有关flask-socketio中服务端和客户端回调函数callback参数的问题(全网最全)
由于工作当中需要用的flask_socketio,所以自己学习了一下如何使用,查阅了有关文档,当看到回调函数callback的时候,发现文档里都描述的不太清楚,最后终于琢磨出来了,分享给有需要的朋友 ...
- Centos6.9 搭建rsync服务端与客户端 案例:全网备份项目
rsync的企业工作场景说明 1)定时备份 1.1生产场景集群架构服务器备份方案项目 借助cron+rsync把所有客户服务器数据同步到备份服务器 2)实时复制 本地数据传输模式(local-only ...
- 【Eureka】服务端和客户端
[Eureka]服务端和客户端 转载:https://www.cnblogs.com/yangchongxing/p/10778357.html Eureka服务端 1.添加依赖 <?xml v ...
- 基于Select模型的Windows TCP服务端和客户端程序示例
最近跟着刘远东老师的<C++百万并发网络通信引擎架构与实现(服务端.客户端.跨平台)>,Bilibili视频地址为C++百万并发网络通信引擎架构与实现(服务端.客户端.跨平台),重新复习下 ...
- asp.net获取服务端和客户端信息
asp.net获取服务端和客户端信息 获取服务器名:Page.Server.ManchineName获取用户信息:Page.User 获取客户端电脑名:Page.Request.UserHostNam ...
随机推荐
- python之random函数
# random各种使用方法 import random # 随机生成[0.1)的浮点数 print("random():", random.random()) # 随机生成100 ...
- Bootstrap缩略图
前面的话 缩略图在网站中最常用的地方就是产品列表页面,一行显示几张图片,有的在图片底部(左侧或右侧)带有标题.描述等信息.Bootstrap框架将这一部独立成一个模块组件,本文将详细介绍Bootstr ...
- Catenyms POJ - 2337(单词+字典序输出路径)
题意: 就是给出几个单词 看能否组成欧拉回路或路径 当然还是让输出组成的最小字典序的路 解析: 还是把首尾字母看成点 把单词看成边 记录边就好了 这题让我对fleury输出最小字典序又加深了一些 ...
- 自学Python1.3-centos内python3并与python2共存
自学Python之路 自学Python1.3-centos内python3并与python2共存 1. 查看是否已经安装Python 测试机系统CentOS 7 默认安装了python2.7, 使用 ...
- 利用Springboot-mail发送邮件
相信使用过Spring的众多开发者都知道Spring提供了非常好用的JavaMailSender接口实现邮件发送.在Spring Boot的Starter模块中也为此提供了自动化配置.下面通过实例看看 ...
- 使用kubeadm部署kubernetes1.9.1+coredns+kube-router(ipvs)高可用集群
由于之前已经写了两篇部署kubernetes的文章,整个过程基本一致,所以这篇只着重说一下coredns和kube-router的部署. kube version: 1.9.1 docker vers ...
- eclipse index 不工作 F3 不能找到头文件
To add paths containing code to parse, follow these steps :1. Right click on the project2. Select Pr ...
- 去除外显子低质量reads时弹出错误“Invalid quality score value (char '#' ord 35 quality value -29) on line 4”和“Invalid quality score value (char '.' ord 46 quality value -18) on line 12”的解决方法
楼主跑以下程序时分别弹出了“fastq_quality_filter: Invalid quality score value (char '.' ord 46 quality value -18) ...
- Java逐行写入字符串到文件
下边是写东西到一个文件中的Java代码.运行后每一次,一个新的文件被创建,并且之前一个也将会被新的文件替代.这和给文件追加内容是不同的. 1. public static void writeFile ...
- 受限玻尔兹曼机(Restricted Boltzmann Machine,RBM)
这篇写的主要是翻译网上一篇关于受限玻尔兹曼机的tutorial,看了那篇博文之后感觉算法方面讲的很清楚,自己收获很大,这里写下来作为学习之用. 原文网址为:http://imonad.com/rbm/ ...