本小節繼續演示如何在 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界面推送實時設備工藝數據,函數代碼如下:
<code>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()
/<code>
解讀:上文代碼與原來的主要差別就是從被動刷新(UI請求後)讀去opc服務的tag位號值,變成間隔time.sleep(2)秒讀取數據後通過request.websocket.send到UI端。
3. 重構 UI 端代碼
這裡 django 與 Flask 的差別就是無須新建一個新的項目,當前項目我們就可以 通過重構 tank4C9.html頁面代碼來使用websocket實時推送功能。
重構後 tank4C9.html代碼如下:
<code>
<title>
Status: 0
OverheadFlow: 0
ButtomsFlow: 0
Power: 0
pushCount: 0
/<code>
解讀: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,代碼如下:
<code># 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),
]
/<code>
4. 調試運行效果
5.小結
本小節我們通過websocket的主動推送方式,完成了實時監控畫面從後臺服務端主動推送到UI端的技術架構迭代,這個過程我們也演示了項目迭代的方式,迭代推進項目功能點的好處非常明顯也就是在一個版本滿足需求的前提下,可以相對從容的採用新的技術和方案升級產品改進性能。
例子我們保留了原來的getCollectorData url,實際的項目開發也是通過增加新推送方法的方式來組織進行的,這樣新的升級也同時滿足原有ajax模式的後臺訪問方式。從而避免升級過程中,前後臺升級版本不一致導致原有頁面不能正常訪問,避免系統已發佈就“崩潰”的“災難”問題。
這裡多說一下敏捷編程下的“小步快跑,快速迭代”模式下,一些團隊遇到的問題就是一開始極簡設計滿足當下要求,然後在不斷功能迭代過程中項目產品架構技術快速老化,可是團隊還是不斷的增加功能點,而沒有人員關心技術架構優化和調整。最終,導致問題越積越多,架構越來越難用,產品構建越來越慢,最後等待一次徹底的項目“重構”。一些“好的”項目應該在過程中逐步演化代碼結構來滿足不斷擴張的功能需求。
敏捷編程的前提是要有一套體系來做保證的,需求管理、代碼重構、單元測試等等,比如:代碼重構在敏捷編程項目過程中就非常重要,一開始簡單滿足需求,一旦發現引入新的需求代碼不能很好的滿足需求的變化時,引入好的設計模式,採用代碼重構的方式來優化代碼結構,並通過迴歸單元測試來保證新的代碼結構能夠正常通過原來的單元測試。盲目的採用敏捷編程又沒有采用它有效管理的一整套機制,最後陷入項目泥潭的,只能說是沒有理解好“敏捷”的核心要素罷了。
閱讀更多 地表嘴強程序員 的文章