【Flask】 flask-socketio实现WebSocket
【flask-socektio】
之前不知道在哪个场合下提到过如何从web后台向前台推送消息。听闻了反向ajax技术这种模式之后,大呼神奇,试了一下之后发现也确实可以用。不过,反向ajax的代价也很明显,只要客户端还和服务端要有信息交互,服务端就必须还维持客户端的这个请求,然后在合适的时候返回。当客户端一多,这么做的成本会比较大。
其他的后端推前端的技术还有类似于隐藏frame,Comet、长轮询等等,没有详细了解过,总之也是各有千秋但也各有利弊。
前不久在开发中碰到了这样一个场景,就是在后台执行一些代码,然后会根据执行的最新情况推送一些提示信息到前台让用户可以知道目前执行到哪一步了。典型就是一个后台向前端推送消息的,而且是比较简单的一个场景。用反向ajax的话好像略显累赘,因为消息的频度还是蛮高的,应该会消费不少网络资源,而且ajax请求的url后执行的程序肯定和后台的工作程序是并行的,如果要获得工作程序的进度信息可能还会涉及到进程间通信问题,总之各种麻烦。最好能找到一种解决方案,可以在后台随时推送数据后在前台实时展示并且允许后台程序继续跑的。
然后找了下就找到了websocket这种html5之后才有的技术。另外再找了下发现了flask-socketio这个拓展模块添加了flask对websocket的支持。
■ 概述
websocket是html5中实现了服务端和客户端进行双向文本或二进制数据通信的一种新协议,其实已经低于HTTP协议本身和HTTP本质上没有什么关系了。不过形式上两者还是有想象之处。因此websocket的连接地址是长这样的:ws://localhost:8080。可以看到,协议修饰符不是http了。
另外,websocket在连接建立阶段是通过HTTP的握手方式进行的,这可以看做是为了兼容浏览器或者使用一些现成的功能来实现,这样一种捷径。当连接建立之后,客户端和服务端之间就不再进行HTTP通信了,所有信息交互都由websocket接管。
从资源占用的角度上来说,其实websocket比ajax占用的资源更多,但它真正实现了全双工通信这一点还是很理想的,意味着无论是前端还是后台的信息交互程序编写都会变得更加方便。由于采用了新的协议,所以我们也需要适当地改造下前后台的程序。
■ 前端ws编写以及socket.io.js
由于是比较新的东西,并不一定所有的浏览器都支持,所有可以用:
if ('WebSocket' in window){
websocket = new WebSocket('ws://localhost:8080');
}
这样的方式来判断是否支持,只有支持的情况下才开始websocket处理
其实光实现双向通信是并没有什么用的,主要还是在通信过程中,让前后端发生一些动作,这就需要添加监听事件。在前端这里,我们可以给websocket这个对象的一些监听回调接口赋值,来规定在不同的场合下前端做些不同的事情。比如:
wesocket.onopen = function(){
alert('建立websocket连接');
}
websocket.onerror = function(){
alert('WebSocket连接发生错误');
}
/****
等等,由于有封装程度更高的js模块,就不扩展写从较底层构建websocket的方法了
****/
● socket.io.js
如果觉得略显麻烦,那么可以用一些已经封装好的websocket的js库,比如socket.io.js。这个库似乎是专门为了node.js设计的,(主要因为网上随便一搜都是把它和node.js结合使用相关的信息。。)不过单独拿出来也能用。引用如果使用cdn方式,那么可以写
<script src="//cdnjs.cloudflare.com/ajax/libs/socket.io/1.3.6/socket.io.min.js"></script>
应用了socket.io.js的一个简单socket对象的创建可以这么写:
var websocket_url = 'http"//' + document.domain + ':' + location.port + '/testnamespace'; //没错是用http开头的url了,因为这个库会自动解析并帮我们创建websocket对象的
//最后的namespace是websocket中的命名空间,后面再讲 var socket = io.connect(wesocket_url);
得到了这个socket对象之后,我们可以用这个对象进行消息的收发。简答的消息收发如下:
//发送消息
socket.emit('request_for_response',{'param':'value'}); //监听回复的消息
socket.on('response',function(data){
if (data.code == '200'){
alert(data.msg);
}
else{
alert('ERROR:' + data.msg);
}
});
其中request_for_response和response两个名字都是我自己取的,这两个名字应该和后端相关的名字协同一致才能保证通信的成功。另外刚才提到了namespace这个东西,因为namespace是在socket创建的时候就决定的,也就是说这些消息的收发都是在'testnamespace'这个空间中进行的。所以在后端上这个空间也要和前端一致。
■ 后端socket编写(flask-socketio)
这里用python的后端来说明。python有socketio这个模块,不过和前端时一样,直接从较为底层的开始编写比较僵硬。各类web框架应该都对websocket有了较好的支持,这里选用了flask这个框架的flask-socketio的扩展。
flask-socketio的创建和运行方式如下:
from flask import Flask
from flask_socketio import SocketIO,emit app = Flask(__name__) socketio = SocketIO()
socketio.init_app(app) """
对app进行一些路由设置
""" """
对socketio进行一些监听设置
""" if __name__ == '__main__':
socketio.run(app,debug=True,host='0.0.0.0',port=5000)
#这里就不再用app.run而用socketio.run了。socketio.run的参数和app.run也都差不多
上面的,对app的路由设置就不再说了,想说的是对socketio的监听设置,这才是真正关系到前后端websocket通信过程的。结合前面的前端代码,socketio的监听设置可以这样做:
@socketio.on('request_for_response',namespace='/testnamespace')
def give_response(data):
value = data.get('param')
#进行一些对value的处理或者其他操作,在此期间可以随时会调用emit方法向前台发送消息
emit('response',{'code':'','msg':'start to process...'})
time.sleep(5)
emit('response',{'code':'','msg':'processed'})
socketio也用了和app.route类似的装饰器的形式进行监听设置。主要参数中有namespace这一项,也就是这项指定了这个监听的范围。在前端,只有注册在testnamespace上的socket,emit向request_for_response的消息才会被这个函数接受并处理。处理函数自带一个参数用来接收前端emit来消息中的那个object,在处理函数中可以对其解析处理。随后后端向前端发送了start to process的消息。也使用了emit这个方法,然后指明了监听是response。也就是说前端on在response上的监听处理函数会处理这个消息(当然还是在testnamespace的框架内)。发出消息后后端不会被阻塞而是继续向下执行,在处理了5秒钟之后发出了结束处理的消息,前端自然隔了五秒之后就得到了这个消息了。
socket监听响应函数本身不需要返回什么值,只需要在处理过程中适当的位置emit出消息即可。
网上其他一些教程中会提到send方法来取代emit方法的位置(无论是前端还是后端),其实send方法就是把上文中的'request_for_response','response'这两个标识都默认成'message'。如此在写的时候就不用写事件名,直接写要传递的参数即可。反过来看,用emit方法实际上是做了一个自定义事件的工作,可以说更加灵活多变一点。
● 略大项目中Manager的支持
一般而言,上面那样的socketio.run总给人感觉是个玩具项目。如果要做一个大型的项目那肯定得用一些更加高端的启动方式才行,另外配置也应该有独立的config.py,通过app.config.form_object的方法来填充配置。
但是经过我的实验,虽然用manager.run可以让socketio工作,但是似乎会存在类似于缓存一样的一种机制。也就是说后台emit出来的信息并不直接发送到前端,而是在整个响应函数执行结束之后一股脑儿的爆出来。不知道是后端发送时进行了缓存还是前端接收时进行了缓存。
所以如果要用websocket的话尽量还是用socketio.run这种方法启动把。至于配置可以在socketio.run中添加类似于debug=current_app.config['DEBUG'],host=current_app.config['HOST']这样的方法。
【Flask】 flask-socketio实现WebSocket的更多相关文章
- python三大web框架Django,Flask,Flask,Python几种主流框架,13个Python web框架比较,2018年Python web五大主流框架
Python几种主流框架 从GitHub中整理出的15个最受欢迎的Python开源框架.这些框架包括事件I/O,OLAP,Web开发,高性能网络通信,测试,爬虫等. Django: Python We ...
- Inside Flask - flask 扩展加载过程
Inside Flask - flask 扩展加载过程 flask 扩展(插件)通常是以 flask_<扩展名字> 为扩展的 python 包名,而使用时,可用 import flask. ...
- Inside Flask - flask.__init__.py 和核心组件
Inside Flask - flask.__init__.py 和核心组件 简单的示例 首先看看一个简单的示例.使用 Flask ,通常是从 flask 模块导入 Flask . request 等 ...
- Inside Flask - Flask 简介
Inside Flask - Flask 简介 前言 Flask 的设计目标是实现一个 wsgi 的微框架,其核心代码保持简单和可扩展性,很容易学习.对于有一定经验初学者而言,跟着例子和一些书的代码来 ...
- Flask - Flask的蓝图(BluePrint)
目录 Flask - Flask的蓝图(BluePrint) 一. 初始Flask蓝图 进阶Flask蓝图 使用蓝图做一个增删改查 1.使用蓝图进行web应用搭建: 2.使用Flask蓝图,查看学生信 ...
- day92:flask:flask简介&基本运行&路由&HTTP请求和响应
目录 1.Flask简介 2.关于使用flask之前的准备 3.flask的基本运行 4.flask加载配置 5.传递路由参数(没有限定类型) 6.传递路由参数(通过路由转换器限定路由参数的类型) 7 ...
- [python][flask] Flask 图片上传与下载例子(支持漂亮的拖拽上传)
目录 1.效果预览 2.新增逻辑概览 3.tuchuang.py 逻辑介绍 3.1 图片上传 3.2 图片合法检查 3.3 图片下载 4.__init__.py 逻辑介绍 5.upload.html ...
- 结合manage.py,在flask项目中使用websocket模块--- flask-socketio
前言: - 为什么我要使用 flask-socketio模块,而不是flask-sockets? - 因为flask-socketio与前端流行的websocket库socke ...
- flask 第五章 WebSocket GeventWebsocket 单聊群聊 握手 解密 加密
1.WebSocket 首先我们来回顾一下,我们之前用socket学习过的项目有: 1.django 2.flask 3.FTP - 文件服务 HTTP - TCP (特点): 1.一次请求,一次响应 ...
随机推荐
- NLP+语篇分析(五)︱中文语篇分析研究现状(CIPS2016)
摘录自:CIPS2016 中文信息处理报告<第三章 语篇分析研究进展.现状及趋势>P21 CIPS2016 中文信息处理报告下载链接:http://cips-upload.bj.bcebo ...
- 3.3.5 DMA写时发生Cache命中的优化
在许多高性能处理器中,还提出了一些新的概念,以加速外设到存储器的DMA写过程.如Freescale的I/O Stashing和Intel的IOAT技术. 如图3?8所示,当设备进行存储器写时,如果可以 ...
- arm上电死机怎么烧写boot
一般上电到死机还有一段时间,在这段时间完成,已经出现两次了.
- php simpleXML操作xml的用法
XML简介 XML是一种流行的半结构化文件格式,以一种类似数据库的格式存储数据.在实际应用中,一些简单的.安全性较低的数据往往使用 XML文件的格式进行存储.这样做的好处一方面可以通过减少与数据库的交 ...
- select(Linux 编程)
select系统调用时用来让我们的程序监视多个文件句柄的状态变化的.程序会停在select这里等待,直到被监视的文件句柄有一个或多个发生了状态改变. 关于文件句柄,其实就是一个整数,通过socket函 ...
- 获取对固定列不重复的新DataTable
获取对固定列不重复的新DataTable ///<summary> /// 获取对固定列不重复的新DataTable /// </summary> ///<param ...
- C#中string类型是值类型还是引用类型?
.Net框架程序设计(修订版)中有这样一段描述:String类型直接继承自Object,这使得它成为一个引用类型,也就是说线程上的堆栈上不会驻留有任何字符串. string类型(引用类型) 名称 CT ...
- 【BZOJ1003】物流运输(动态规划,最短路)
[BZOJ1003]物流运输(动态规划,最短路) 题面 Description 物流公司要把一批货物从码头A运到码头B.由于货物量比较大,需要n天才能运完.货物运输过程中一般要转停好几个码头.物流公司 ...
- 【BZOJ2330】【SDOI2012】糖果(差分约束,SPFA)
[BZOJ2330][SDOI2012]糖果 题面 题目描述 幼儿园里有N个小朋友,lxhgww老师现在想要给这些小朋友们分配糖果,要求每个小朋友都要分到糖果.但是小朋友们也有嫉妒心,总是会提出一些要 ...
- [Luogu3936]Coloring
Luogu sol 模拟退火呀 初始状态按顺序涂色,让同种颜色尽量放在一起. 每次随机交换两个位置,注意\(\Delta\)的计算 瞎JB调一下参数就行了 可以多做几次避免陷入局部最优解 code # ...