django进阶02websocket
原创博文地址:django进阶02websocket
本文适合有一定websocket基础的,至少完整看过前后端demo的读者,一窍不通的小白建议先阅读“参考”部分的博文扫扫盲。
基于django的dwebsocket组件(目前虽然不在维护,但正常使用没问题)
前端方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
<script type="text/javascript">var socket = new WebSocket("ws:" + window.location.host + "/drug/drug_connect/");socket.onopen = function () {console.log('WebSocket open');//成功连接上Websocketsocket.send('adasdasda。。。。');//发送数据到服务端};socket.onmessage = function (e) {console.log('message: ' + e.data);//打印服务端返回的数据};socket.onclose=function(e){console.log(e);socket.close(); //关闭TCP连接};if (socket.readyState == WebSocket.OPEN) socket.onopen(); </sctipt> |
由于js的异步友好性,所以代码看起来非常清爽,也容易理解。socket连接,成功后干什么(onopen),收到消息后干嘛(onmessage),如何关闭等。而且也会自动发送Pingpong包确保连接的保持。
后端方法
dwebsocket的一些内置方法:
request.is_websocket():判断请求是否是websocket方式,是返回true,否则返回false
request.websocket: 当请求为websocket的时候,会在request中增加一个websocket属性,
WebSocket.wait() 返回客户端发送的一条消息,没有收到消息则会导致阻塞
WebSocket.read() 和wait一样可以接受返回的消息,只是这种是非阻塞的,没有消息返回None
WebSocket.count_messages()返回消息的数量
WebSocket.has_messages()返回是否有新的消息过来
WebSocket.send(message)像客户端发送消息,message为byte类型
后端方法相对前端就没有那么友好了。如果面对一个特定需求如何实现呢?
场景1,1v0聊天
这个实际业务中没啥用,仅用来验证websocket接口性质,了解接口特性而已。
1 2 3 4 5 6 7 8 9 10 |
@accept_websocket def start_server_script(request):if request.is_websocket():# "这里实现wbsocket连接逻辑"for info in request.websocket:# 这里需要注意的是,这个for后面的对象,request.websocket是阻塞的,也就是说如果对方发送消息,info=新消息,循环走一圈,如果对方不发消息,for这里会“卡住”,这里容易忽略request.websocket.send("你刚才对我说:%s"%info)print('这里其实不会被执行')else:# "这里实现http连接逻辑"pass |
场景2,多v多聊天
上面的例子很简单吧,自己和自己聊天,多v多聊天代码和上面差不多!
将request.websocket看做普通对象,将所所有连接的websocket保存全局变量中,依次send(msg)即可.
1 2 3 4 5 6 7 8 9 10 11 12 |
wobsocket_map=dict() @accept_websocket def start_server_script(request):if request.is_websocket():wobsocket_map[id(request.websocket)]=request.websocket# "这里实现wbsocket连接逻辑"for info in request.websocket:# 这里需要注意的是,这个for后面的对象,request.websocket是阻塞的,也就是说如果对方发送消息,info=新消息,循环走一圈,如果对方不发消息,for这里会“卡住”,这里容易忽略[websocket.send("你刚才对我说:%s"%info) for websocket in wobsocket_map.values()]print('这里其实不会被执行')else:# "这里实现http连接逻辑"pass |
可以实现效果,将msg发送给所有连接到此websocket的对象!
场景3,视频播放
视频播放是一种类似死循环的处理逻辑
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
# 伪代码,不保证能跑,意思差不多 # 其他函数通过next(),or .send()调用此生成器,不断生成各个视频帧的base64编码(看不懂的话,百度"yield") url='rtmp://xxxx' @accept_websocket def show_video(request):video=video_img_base64(url)base64=next(video)while base64 is not None: # 这个就是类似死循环的东西(当然这个并非真正死循环,但很多情况退出只能放到循环里break,这里只能采用while True)request.websocket.send({'img_base64':base64})base64=video.send(None)def video_img_base64(url):cap=cv2.VideoCapture(url)ret,frame=cap.read()while ret:yield base64(frame.tobytes()).decode('utf8')ret,frame=cap.read()else:yield None #调用方一旦收到None,避免调用next() or send()否则抛出异常,需要做异常处理 |
场景4,视频播放及控制
相比前面的例子,多了控制逻辑,那么问题来了,控制逻辑放哪里?
如果后台也可以向js那样,onmessage(xxx),这样就简单多了,onmessage(),根据message修改一个类似全局变量的东西就行。但是并没有。
从场景1的例子可以看出,websocket非常擅长处理request-response的情况。例子3,看到其也可以处理 持续response推送的情况,那么如何实现类似异步里面交互式响应呢?
这里提供一个简单模板
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
send_queue=Queue() @accept_websocket def websocket_ctrl(request):if request.is_websocket:while True:# 由于使用同步方式处理异步,所以这里必然死循环if request.websocket.count_messages()>0:message=request.websocket.read()while message:onmessage(message)message=request.websocket.read()if not send_queue.empty:# 需向send_queue放东西,send函数中会放messagemesssage=send_queue.pop()while message:message=request.websocket.send(message)messsage=send_queue.pop()def onmessage(message):pass # 这里可以放你想在收到消息时做的事情,类似异步方法的onmessage,如果需要反馈修改,比如改变上一级的执行逻辑,则可以通过返回值的方式,传递给上一级调用者,让上一级调用者通过返回值调整自身执行逻辑# 他人调用这个方法,将消息加入发送队列,在websocket_ctrl的循环中会取得,并发出 def send(message):send_queue.put(message) |
注意:尽可能避免使用
1 2 |
for message in request.websocket:print(message) |
由于其会导致阻塞,特别强调这一点,因为大多数情况,我们看到for循环,会想当然以为”它很快会结束“,其实未必。
还有一点就是需要加异常处理,对方可能主动关闭连接,此时后台如果发送消息,会抛出异常。
总结
流程图
方法 | 典型使用形态 | 阻塞 | 开启连接 | (客户端)发送消息 | (客户端)断开连接 |
---|---|---|---|---|---|
request.websocket | for msg in request.websocket:func(msg) | 是 | halt:request.websocket | msg<=’common msg’ | msg<=None |
request.websocket.wait() | while True: msg=request.websocket.wait() | 是 | halt:request.websocket.wait() | msg<=’common msg’ | msg<=None |
request.websocket.read() | while True:msg=request.websocket.read() | 否 | loop:msg<=request.websocket.read() | msg<=request.websocket.read() | except |
request.websocket.has_messages() | while True:has_msg=request.websocket.has_messages();if has_msg:msg=request.websocket.read() | 否 | loop:has_msg<=request.websocket.has_messages() | msg<=request.websocket.read() | has_msg=True and msg=None |
request.websocket.count_messages() | while True:count=request.websocket.count_messages();if count>0:msg=request.websocket.read() | 否 | loop:count<=request.websocket.count_messages() | msg<=request.websocket.read() | count>0 and msg=None |
多重捕获会怎样?直观理解即可,只能有一个捕获到消息,不会重复捕获。
参考
https://www.520pf.cn/article/135.html
https://blog.csdn.net/xianailili/article/details/82180114
django进阶02websocket相关推荐
- django进阶07用户模块与权限系统
原创:django进阶07用户模块与权限系统 Django默认提供了用户权限管理模块auth, 1 2 3 user表,User是auth模块中维护用户信息的表,在数据库中该表被命名为auth_use ...
- django进阶06数据库事务
原创:django进阶06数据库事务 锁 1.1:乐观锁: 概念:同一条数据很少会因为并发修改而产生冲突,适用于读多写少的场景. 实现方式:读取一个字段,执行处理逻辑,当需要更新数据时,再次检查该字段 ...
- django进阶05中间件
原创:django进阶05中间件 django进阶05中间件 什么是中间件 django的中间件(middleware)是一个轻量级的插件系统,在django中的请求和响应中,可以利用中间件干预视图的 ...
- django进阶04部署上线(nginx,uwsgi,supervisor)
原创博文地址:django进阶04部署上线(nginx,uwsgi,supervisor) django自身服务ok python manage.py runserver,验证可正常访问 uwsgi安 ...
- django进阶03静态文件和模板
原创博文地址:django进阶03静态文件和模板 静态文件和模板 静态文件:css,js,image,如果作为纯粹的web应用来看,静态文件的响应并不属于web应用范畴,因为静态文件不涉及业务逻辑,也 ...
- Django进阶教程
Django进阶教程 Queryset特性及高级查询技巧 什么是QuerySet QuerySet是Django提供的强大的数据库接口(API).正是因为通过它,我们可以使用filter, exclu ...
- Django进阶: 如何自定义manage.py管理命令
每次在启动Django服务之前,我们都会在终端运行python manage.py xxx的管理命令.其实我们还可以自定义管理命令,这对于执行独立的脚本或任务非常有用,比如清除缓存.导出用户邮件清单或 ...
- Yuan先生博客-Django进阶
Django基础 编号 标题 链接地址 1 Django-进阶 Link 2 Django-admin管理工具 Link 3 Django-组件拾遗 Link 4 Django-form表单 Link ...
- Python 第五阶段 学习记录之---Django 进阶
Model 一.创建表 1.基本结构 字段 1 AutoField(Field) 2 - int自增列,必须填入参数 primary_key=True 3 4 BigAutoField(AutoFie ...
最新文章
- Oracle 升级10.2.0.5.4 OPatch 报错Patch 12419392 Optional component(s) missing 解决方法
- 关于分布式事务、两阶段提交协议、三阶提交协议
- Firefox联手Chrome合作开发网页VR标准
- 基于jQuery的表单验证插件:jValidate
- python集合数据对象_python学习第七天 基础数据类型补充 深浅copy 集合 关键字后面加可迭代对象...
- 基于tutk方案的p2p源码_以太坊源码分析--p2p节点发现
- 双系统安装ubuntu后没有windows启动项
- BCGControlBar入门使用手册
- JWT token信息保存
- android 怎么获取app 字体颜色,Android APP使用自定义字体实现方法
- MySoft.Data新版v2.7.3 beta发布,修正较多bug,新增功能尚未完全测试
- Fragment与Activity
- linux sh 按键精灵,按键精灵脚本代码教程
- python参数估计(一个总体均值)
- C#打印pdf遇到的问题
- GPIO output level 和 GPIO Pull-up/Pull-down的区别
- 微信小程序picker多列选择器:mode = multiSelector
- 找规律万能公式_初中规律题的万能公式
- 阿里云RPA操作——当前窗口截图
- 射频器件厂商RFMD与TriQuint达成合并协议