Ajax輪詢是經過特定的的時間間隔(如每1秒),由瀏覽器對服務器發出HTTP請求,而後由服務器返回最新的數據給客戶端的瀏覽器。這種簡單粗暴模式有一個明顯的缺點,就是瀏覽器須要不斷的向服務器發出請求,HTTP請求可能包含較長的頭部,其中真正有效的數據可能只是很小的一部分,顯然這樣會浪費不少的帶寬等資源(對於不少局域網內的企業應用,這個簡單粗暴模式確實解決問題)。html
本文接下來採用一種更加高效率的服務端主動推送技術(WebSocket )來提升數據的傳輸效率。WebSocket通訊協議 是 HTML5 開始支持的一種在單個 TCP 鏈接上進行全雙工通信的協議。在 WebSocket 技術架構中,瀏覽器和服務器只須要完成一次握手,二者之間就直接能夠建立持久性的鏈接,並進行雙向數據傳輸。python
瀏覽器經過 JavaScript 向服務器發出創建 WebSocket 鏈接的請求,鏈接創建之後,客戶端和服務器端就能夠經過 TCP 鏈接直接交換數據。當你獲取 Web Socket 鏈接後,能夠經過 send() 方法來向服務器發送數據,並經過 onmessage 事件來接收服務器返回的數據。 git
本例咱們經過VS2019建立一個空的Python項目,來實現Flask-Sockets服務端代碼,咱們在現有的解決方案裏添加一個Project,以下圖:github
Flask咱們可採用Flask-Sockets組件來實現websocket 通訊驗證原型,web
組件網址:https://github.com/heroku-python/flask-socketsflask
安裝命令:pip install Flask-Sockets瀏覽器
vs community 咱們能夠直接在Python Environment 安裝Flask-Sockets組件(注意字母大小寫,不然不能安裝成功),以下圖:服務器
服務端先實現由服務端定時推送一個自增的變量值給客戶端,代碼以下:websocket
from flask import Flask from flask_sockets import Sockets import time app = Flask(__name__) sockets = Sockets(app) @sockets.route('/tagCurValue') def tagCurValue(ws): ''' 代碼模擬每5秒鐘,定時給客戶端推送一個自增的變量數據 ''' n=0 while not ws.closed: n=n+1 ws.send(str(n)) print("tag curent value:"+ str(n)) time.sleep(5) @app.route('/') def hello(): return 'Hello World!' if __name__ == "__main__": from gevent import pywsgi from geventwebsocket.handler import WebSocketHandler server = pywsgi.WSGIServer(('0.0.0.0', 5000), application=app, handler_class=WebSocketHandler) print('Server Start') server.serve_forever()
server = pywsgi.WSGIServer(('0.0.0.0', 5000), application=app, handler_class=WebSocketHandler)網絡
上述代碼的'0.0.0.0'要注意賦值,組件的Example例子是一個空字符串,筆者也踩了坑,花費很多時間才找到案例運行失敗的緣由。
首先,咱們須要把FlaskSocketSvr設置成解決方案的默認項目,後然F5運行測試環境以下圖:
瀏覽器地址欄輸入如下網址:http://127.0.0.1:5000/ 結果以下圖:
如今咱們重構客戶端代碼以即可以訪問服務端提升的websocket URL得到數據更新
http://127.0.0.1:5000/tagCurValue
UI JS代碼以下:
//JQuery 代碼入口 $(document).ready(function(){ //setInterval("getData()",3000); if ("WebSocket" in window) { //鏈接server--TagCurValue var ws = new WebSocket("ws://127.0.0.1:5000/tagCurValue"); //var ws = new WebSocket("ws://127.0.0.1:8008/tagCurValue"); ws.onmessage = function (evt) { // 接收數據 receivedMsg = evt.data; $("#divTag").html(receivedMsg); }; } });
如今咱們在Project經過Python菜單執行Start server,而後再F5運行服務端,咱們就能夠經過瀏覽器運行測試頁面了。
測試頁面url:http://127.0.0.1:8008/
咱們也能經過瀏覽器的開發工具查看網絡訪問只發生了一次。
最後,咱們再把tagCurValue'重構成真正讀取opc服務某一個tag位號的值。以完成了從UI端到服務端主動獲取opc服務tag位號值,並更新UI界面的技術原型。views文件函數tagCurValue'代碼修改以下:
@sockets.route('/tagCurValue') def tagCurValue(ws): import OpenOPC while not ws.closed: opc = OpenOPC.client() opc.connect('Matrikon.OPC.Simulation') result= opc['Random.Int1'] opc.close() ws.send(unicode( result)) print("tag curent value:"+ unicode( result)) time.sleep(5)
如今,咱們從新運行測試環境,結果以下圖:
本小節介紹瞭如何經過採用websocket技術,實現由服務端主動Send數據到UI端的通訊模式,客戶端實時刷新UI端tag位號的當前值,提升了數據傳輸的效率和性能,樣例的FlaskSocketSvr服務也演示了一個獨立的服務端到UI端的數據傳輸方式(獨立的服務端地址)。最後,新的服務也經過讀取OPC server的tag位號值演示了經過OPC Sever獲取監控設備數據的方式。