本小节继续演示如何在 Django 项目中采用 早期websocket 技术 原型 来实现把 OPC 服务端数据实时推送到 UI 端,让监控页面 在另一种技术方式下,实时显示现场设备的工艺数据变化情况。本例我们仍然采用比较轻量级的dwebsocket组件。
1. 安装 dwebsocket 组件
安装命令: pip install dwebsocket
1.1. dwebsocket 使用方法
如果你想为一个单独的视图处理一个websocket连接可以使用 accept_websocket 装饰器,它会将标准的 HTTP 请求路由到视图中。使用 require_websocke 装饰器只允许使用 WebSocket 连接,会拒绝正常的 HTTP 请求。
在设置中添加设置MIDDLEWARE_CLASSES=dwebsocket.middleware.WebSocketMiddleware这样会拒绝单独的视图使用websocket,必须加上 accept_websocket 装饰器。
设置WEBSOCKET_ACCEPT_ALL=True可以允许每一个单独的视图实用 websockets
1.2.常用方法和属性
1.request.is_websocket()如果是个websocket 请求返回 True ,如果是个普通的 http 请求返回 False, 可以用这个方法区分它们。
2.request.websocket 在一个 websocket 请求建立之后,这个请求将会有一个 websocket 属性,用来给客户端提供一个简单的 api 通讯,如果 request.is_websocket() 是 False ,这个属性将是 None 。
3.WebSocket.wait() 返回一个客户端发送的信息,在客户端关闭连接之前他不会返回任何值,这种情况下,方法将返回 None
4.WebSocket.read() 如果没有从客户端接收到新的消息, read 方法会返回一个新的消息,如果没有,就不返回。这是一个替代 wait 的非阻塞方法
5.WebSocket.count_messages() 返回消息队列数量
6.WebSocket.has_messages() 如果有新消息返回 True ,否则返回 False
7.WebSocket.send(message) 向客户端发送消息
8.WebSocket.__iter__()websocket 迭代器
dwebsocket使用起来比较简单,增加一个简单的服务端url和重构UI代码;UI代码创建一个websocket连接并在onmessage 事件里处理返回的数据即可,不用花费多大的代价就能快速让监控页面升级到一个新的方式下,下面看代码演进吧。
2. 重构服务端代码 —— 增加一个推送的 websocket url
使用accept_websocket 装饰器在 Collector APP 的 views 文件中增加一个 pushCollector 的方法,实现 UI端连接上服务端后,服务端使用websocket主动向UI界面推送实时设备工艺数据,函数代码如下:
from dwebsocket.decorators import accept_websocket import OpenOPC @accept_websocket def pushCollectorData(request): tank4C9={ 'DeviceId': 1, 'DeviceName':'1#反应罐', 'Status': 0, #设备运行状态 'OverheadFlow':0 ,#'顶流量', 'ButtomsFlow': 0, #'低流量' 'Power': 0, #功率 } Collector={ 'CollectorId': 1, 'CollectorName':'1#采集器', 'Status': 0, 'DeviceList':[tank4C9], } Collector={ 'CollectorId': 1, 'CollectorName':'1#采集器', 'Status': 0, 'DeviceList':[tank4C9], } if request.is_websocket(): try: while True: opc = OpenOPC.client() opc.connect('Matrikon.OPC.Simulation') tank4C9['OverheadFlow']= opc['Random.Int1'] tank4C9['ButtomsFlow']= opc['Random.Int2'] tank4C9['Power']= opc['Random.Int4'] opc.close() request.websocket.send(\ json.dumps( {"rows":[Collector],'total':1})) time.sleep(2) finally: client.disconnect()
解读:上文代码与原来的主要差别就是从被动刷新(UI请求后)读去opc服务的tag位号值,变成间隔time.sleep(2)秒读取数据后通过request.websocket.send到UI端。
3. 重构 UI 端代码
这里 django 与 Flask 的差别就是无须新建一个新的项目,当前项目我们就可以 通过重构 tank4C9.html页面代码来使用websocket实时推送功能。
重构后 tank4C9.html代码如下:
Status: 0OverheadFlow: 0ButtomsFlow: 0Power: 0pushCount: 0
解读:UI端代码通过ws.onmessage事件更新页面显示,对照上一张的ajax轮询模式的代码,代码的主体结构和功能并没有大的变化,只是采用了一种的新的数据传递方式而已。
注意 :
var ws = new WebSocket("ws://127.0.0.1:8090/pushCollector/");
pushCollector/ url 最后那个“ /”,这个点是 django 与 flask 的一个差别,否则我们创建这个 websocket 时会收到 301 错误提示!
4. 发布pushCollectorData url
项目的 urls 发布这新的 url 接口地址,这例我们保留原来的getCollectorData,代码如下:
# Uncomment next two lines to enable admin: #from django.contrib import admin from django.urls import path from Collector import views urlpatterns = [ # Uncomment the next line to enable the admin: #path('admin/', admin.site.urls) path('tank4C9/', views.tank4C9), path('getCollectorData/', views.getCollectorData), path('pushCollectorData/', views.pushCollectorData), ]
本小节我们通过websocket的主动推送方式,完成了实时监控画面从后台服务端主动推送到UI端的技术架构迭代,这个过程我们也演示了项目迭代的方式,迭代推进项目功能点的好处非常明显也就是在一个版本满足需求的前提下,可以相对从容的采用新的技术和方案升级产品改进性能。
例子我们保留了原来的getCollectorData url,实际的项目开发也是通过增加新推送方法的方式来组织进行的,这样新的升级也同时满足原有ajax模式的后台访问方式。从而避免升级过程中,前后台升级版本不一致导致原有页面不能正常访问,避免系统已发布就“崩溃”的“灾难”问题。
这里多说一下敏捷编程下的“小步快跑,快速迭代”模式下,一些团队遇到的问题就是一开始极简设计满足当下要求,然后在不断功能迭代过程中项目产品架构技术快速老化,可是团队还是不断的增加功能点,而没有人员关心技术架构优化和调整。最终,导致问题越积越多,架构越来越难用,产品构建越来越慢,最后等待一次彻底的项目“重构”。一些“好的”项目应该在过程中逐步演化代码结构来满足不断扩张的功能需求。
敏捷编程的前提是要有一套体系来做保证的,需求管理、代码重构、单元测试等等,比如:代码重构在敏捷编程项目过程中就非常重要,一开始简单满足需求,一旦发现引入新的需求代码不能很好的满足需求的变化时,引入好的设计模式,采用代码重构的方式来优化代码结构,并通过回归单元测试来保证新的代码结构能够正常通过原来的单元测试。盲目的采用敏捷编程又没有采用它有效管理的一整套机制,最后陷入项目泥潭的,只能说是没有理解好“敏捷”的核心要素罢了。
源码获取加群:850591259