欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

flask-socketio實現(xiàn)WebSocket的方法

 更新時間:2018年07月31日 14:07:27   作者:K.Takanashi  
這篇文章主要介紹了flask-socketio實現(xiàn)WebSocket的方法,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧

【flask-socektio】

之前不知道在哪個場合下提到過如何從web后臺向前臺推送消息。聽聞了反向ajax技術(shù)這種模式之后,大呼神奇,試了一下之后發(fā)現(xiàn)也確實可以用。不過,反向ajax的代價也很明顯,只要客戶端還和服務(wù)端要有信息交互,服務(wù)端就必須還維持客戶端的這個請求,然后在合適的時候返回。當(dāng)客戶端一多,這么做的成本會比較大。

其他的后端推前端的技術(shù)還有類似于隱藏frame,Comet、長輪詢等等,沒有詳細了解過,總之也是各有千秋但也各有利弊。

前不久在開發(fā)中碰到了這樣一個場景,就是在后臺執(zhí)行一些代碼,然后會根據(jù)執(zhí)行的最新情況推送一些提示信息到前臺讓用戶可以知道目前執(zhí)行到哪一步了。典型就是一個后臺向前端推送消息的,而且是比較簡單的一個場景。用反向ajax的話好像略顯累贅,因為消息的頻度還是蠻高的,應(yīng)該會消費不少網(wǎng)絡(luò)資源,而且ajax請求的url后執(zhí)行的程序肯定和后臺的工作程序是并行的,如果要獲得工作程序的進度信息可能還會涉及到進程間通信問題,總之各種麻煩。最好能找到一種解決方案,可以在后臺隨時推送數(shù)據(jù)后在前臺實時展示并且允許后臺程序繼續(xù)跑的。

然后找了下就找到了websocket這種html5之后才有的技術(shù)。另外再找了下發(fā)現(xiàn)了flask-socketio這個拓展模塊添加了flask對websocket的支持。

概述

websocket是html5中實現(xiàn)了服務(wù)端和客戶端進行雙向文本或二進制數(shù)據(jù)通信的一種新協(xié)議,其實已經(jīng)低于HTTP協(xié)議本身和HTTP本質(zhì)上沒有什么關(guān)系了。不過形式上兩者還是有想象之處。因此websocket的連接地址是長這樣的:ws://localhost:8080。可以看到,協(xié)議修飾符不是http了。

另外,websocket在連接建立階段是通過HTTP的握手方式進行的,這可以看做是為了兼容瀏覽器或者使用一些現(xiàn)成的功能來實現(xiàn),這樣一種捷徑。當(dāng)連接建立之后,客戶端和服務(wù)端之間就不再進行HTTP通信了,所有信息交互都由websocket接管。

從資源占用的角度上來說,其實websocket比ajax占用的資源更多,但它真正實現(xiàn)了全雙工通信這一點還是很理想的,意味著無論是前端還是后臺的信息交互程序編寫都會變得更加方便。由于采用了新的協(xié)議,所以我們也需要適當(dāng)?shù)馗脑煜虑昂笈_的程序。

前端ws編寫以及socket.io.js

由于是比較新的東西,并不一定所有的瀏覽器都支持,所有可以用:

if ('WebSocket' in window){
 websocket = new WebSocket('ws://localhost:8080');
}

這樣的方式來判斷是否支持,只有支持的情況下才開始websocket處理

其實光實現(xiàn)雙向通信是并沒有什么用的,主要還是在通信過程中,讓前后端發(fā)生一些動作,這就需要添加監(jiān)聽事件。在前端這里,我們可以給websocket這個對象的一些監(jiān)聽回調(diào)接口賦值,來規(guī)定在不同的場合下前端做些不同的事情。比如:

wesocket.onopen = function(){
  alert('建立websocket連接');
}

websocket.onerror = function(){
  alert('WebSocket連接發(fā)生錯誤');
}

/****
等等,由于有封裝程度更高的js模塊,就不擴展寫從較底層構(gòu)建websocket的方法了
****/

 socket.io.js

如果覺得略顯麻煩,那么可以用一些已經(jīng)封裝好的websocket的js庫,比如socket.io.js。這個庫似乎是專門為了node.js設(shè)計的,(主要因為網(wǎng)上隨便一搜都是把它和node.js結(jié)合使用相關(guān)的信息。。)不過單獨拿出來也能用。引用如果使用cdn方式,那么可以寫

<script src="http://cdnjs.cloudflare.com/ajax/libs/socket.io/1.3.6/socket.io.min.js"></script>

應(yīng)用了socket.io.js的一個簡單socket對象的創(chuàng)建可以這么寫:

var websocket_url = 'http"http://' + document.domain + ':' + location.port + '/testnamespace';
//沒錯是用http開頭的url了,因為這個庫會自動解析并幫我們創(chuàng)建websocket對象的
//最后的namespace是websocket中的命名空間,后面再講
var socket = io.connect(wesocket_url);

得到了這個socket對象之后,我們可以用這個對象進行消息的收發(fā)。簡答的消息收發(fā)如下:

//發(fā)送消息
socket.emit('request_for_response',{'param':'value'});
//監(jiān)聽回復(fù)的消息
socket.on('response',function(data){
  if (data.code == '200'){
    alert(data.msg);
  }
  else{
    alert('ERROR:' + data.msg);
  }
});

其中request_for_response和response兩個名字都是我自己取的,這兩個名字應(yīng)該和后端相關(guān)的名字協(xié)同一致才能保證通信的成功。另外剛才提到了namespace這個東西,因為namespace是在socket創(chuàng)建的時候就決定的,也就是說這些消息的收發(fā)都是在'testnamespace'這個空間中進行的。所以在后端上這個空間也要和前端一致。

后端socket編寫(flask-socketio)

這里用python的后端來說明。python有socketio這個模塊,不過和前端時一樣,直接從較為底層的開始編寫比較僵硬。各類web框架應(yīng)該都對websocket有了較好的支持,這里選用了flask這個框架的flask-socketio的擴展。

flask-socketio的創(chuàng)建和運行方式如下:

from flask import Flask 
from flask_socketio import SocketIO,emit
app = Flask(__name__)
socketio = SocketIO()
socketio.init_app(app)
"""
對app進行一些路由設(shè)置
"""
"""
對socketio進行一些監(jiān)聽設(shè)置
"""
if __name__ == '__main__':
  socketio.run(app,debug=True,host='0.0.0.0',port=5000)
  #這里就不再用app.run而用socketio.run了。socketio.run的參數(shù)和app.run也都差不多

上面的,對app的路由設(shè)置就不再說了,想說的是對socketio的監(jiān)聽設(shè)置,這才是真正關(guān)系到前后端websocket通信過程的。結(jié)合前面的前端代碼,socketio的監(jiān)聽設(shè)置可以這樣做:

@socketio.on('request_for_response',namespace='/testnamespace')
def give_response(data):
  value = data.get('param')
  #進行一些對value的處理或者其他操作,在此期間可以隨時會調(diào)用emit方法向前臺發(fā)送消息
  emit('response',{'code':'200','msg':'start to process...'})
  time.sleep(5)
  emit('response',{'code':'200','msg':'processed'})

socketio也用了和app.route類似的裝飾器的形式進行監(jiān)聽設(shè)置。主要參數(shù)中有namespace這一項,也就是這項指定了這個監(jiān)聽的范圍。在前端,只有注冊在testnamespace上的socket,emit向request_for_response的消息才會被這個函數(shù)接受并處理。處理函數(shù)自帶一個參數(shù)用來接收前端emit來消息中的那個object,在處理函數(shù)中可以對其解析處理。隨后后端向前端發(fā)送了start to process的消息。也使用了emit這個方法,然后指明了監(jiān)聽是response。也就是說前端on在response上的監(jiān)聽處理函數(shù)會處理這個消息(當(dāng)然還是在testnamespace的框架內(nèi))。發(fā)出消息后后端不會被阻塞而是繼續(xù)向下執(zhí)行,在處理了5秒鐘之后發(fā)出了結(jié)束處理的消息,前端自然隔了五秒之后就得到了這個消息了。

socket監(jiān)聽響應(yīng)函數(shù)本身不需要返回什么值,只需要在處理過程中適當(dāng)?shù)奈恢胑mit出消息即可。

網(wǎng)上其他一些教程中會提到send方法來取代emit方法的位置(無論是前端還是后端),其實send方法就是把上文中的'request_for_response','response'這兩個標識都默認成'message'。如此在寫的時候就不用寫事件名,直接寫要傳遞的參數(shù)即可。反過來看,用emit方法實際上是做了一個自定義事件的工作,可以說更加靈活多變一點。

略大項目中Manager的支持

一般而言,上面那樣的socketio.run總給人感覺是個玩具項目。如果要做一個大型的項目那肯定得用一些更加高端的啟動方式才行,另外配置也應(yīng)該有獨立的config.py,通過app.config.form_object的方法來填充配置。

但是經(jīng)過我的實驗,雖然用manager.run可以讓socketio工作,但是似乎會存在類似于緩存一樣的一種機制。也就是說后臺emit出來的信息并不直接發(fā)送到前端,而是在整個響應(yīng)函數(shù)執(zhí)行結(jié)束之后一股腦兒的爆出來。不知道是后端發(fā)送時進行了緩存還是前端接收時進行了緩存。

所以如果要用websocket的話盡量還是用socketio.run這種方法啟動把。至于配置可以在socketio.run中添加類似于debug=current_app.config['DEBUG'],host=current_app.config['HOST']這樣的方法。

以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

最新評論