Flask-SocketIO 簡單使用指南

Flask-SocketIO 使 Flask 應用程序能夠訪問客戶端和服務器之間的低延遲雙向通信。客戶端應用程序可以使用 Javascript,C ++,Java 和 Swift 中的任何 SocketIO 官方客戶端庫或任何兼容的客戶端來建立與服務器的永久連接。

安裝

直接使用 pip 來安裝:

pip install flask-socketio
復制代碼

要求

Flask-SocketIO 兼容 Python 2.7 和 Python 3.3+。可以從以下三個選項中選擇此程序包所依賴的異步服務:

  • eventlet 性能最佳,支持長輪詢和 WebSocket 傳輸。
  • gevent 在許多不同的配置中得到支持。gevent 包完全支持長輪詢傳輸,但與 eventlet 不同,gevent 沒有本機 WebSocket 支持。要添加對 WebSocket 的支持,目前有兩種選擇:安裝 gevent-websocket 包為 gevent 增加 WebSocket 支持,或者可以使用帶有 WebSocket 功能的 uWSGI Web 服務器。gevent 的使用也是一種高性能選項,但略低于 eventlet。
  • 也可以使用基于 Werkzeug 的 Flask 開發服務器,但需要注意的是,它缺乏其他兩個選項的性能,因此它只應用于簡單的開發環境。此選項僅支持長輪詢傳輸。

擴展會根據安裝的內容自動檢測要使用的異步框架。優先考慮 eventlet,然后是 gevent。對于 gevent 中的WebSocket 支持,首選 uWSGI,然后是 gevent-websocket。如果既未安裝 eventlet 也未安裝 gevent,則使用 Flask 開發服務器。

如果使用多個進程,則進程使用消息隊列服務來協調諸如廣播之類的操作。支持的隊列是 Redis,RabbitMQ以及 Kombu 軟件包支持的任何其他消息隊列 。

在客戶端,官方 Socket.IO Javascript 客戶端庫可用于建立與服務器的連接。還有使用 Swift,Java 和 C ++ 編寫的官方客戶端。非官方客戶端也可以工作,只要它們實現 Socket.IO協議。

初始化

以下代碼示例演示如何將 Flask-SocketIO 添加到 Flask 應用程序:

from flask import Flask, render_template
from flask_socketio import SocketIOapp = Flask(__name__)
app.config['SECRET_KEY'] = 'secret!'
socketio = SocketIO(app)if __name__ == '__main__':socketio.run(app, host='0.0.0.0', debug=True)
復制代碼

以上代碼即完成了一個簡單的 Web 服務器。

socketio.run()函數封裝了 Web 服務器的啟動,并替換了app.run()標準的 Flask 開發服務器啟動。

當應用程序處于調試模式時,Werkzeug 開發服務器仍然在內部使用和配置正確socketio.run()

在生產模式中,如果可用,則使用 eventlet Web 服務器,否則使用 gevent Web 服務器。如果未安裝 eventlet 和gevent,則使用 Werkzeug 開發 Web 服務器。

基于 Flask 0.11 中引入的單擊的命令行界面。此擴展提供了適用于啟動 Socket.IO 服務器的新版本命令。用法示例:flask run

$ FLASK_APP=my_app.py flask run
復制代碼

或者直接使用下面方式,也可以啟動項目:

$ python2.7 app.py
復制代碼

連接事件

Flask-SocketIO 調度連接和斷開事件。以下示例顯示如何為它們注冊處理程序:

@socketio.on('connect', namespace='/test')
def test_connect():emit('my response', {'data': 'Connected'})@socketio.on('disconnect', namespace='/test')
def test_disconnect():print('Client disconnected')
復制代碼

連接事件處理程序可以選擇返回False以拒絕連接。這樣就可以在此時對客戶端進行身份驗證。

請注意,連接和斷開連接事件將在使用的每個命名空間上單獨發送。

接收消息

使用 SocketIO 時,雙方都會將消息作為事件接收。在客戶端使用 Javascript 回調。使用 Flask-SocketIO,服務器需要為這些事件注冊處理程序,類似于視圖函數處理路由的方式。

以下示例為未命名的事件創建服務器端事件處理程序:

@socketio.on('message')
def handle_message(message):print('received message: ' + message)
復制代碼

上面的示例使用字符串消息。另一種類型的未命名事件使用 JSON 數據:

@socketio.on('json')
def handle_json(json):print('received json: ' + str(json))
復制代碼

最靈活的方式是使用自定義事件名稱,在開發過程中最常用的也是這種方式。

事件的消息數據可以是字符串,字節,整數或 JSON:

@socketio.on('my event')
def handle_my_custom_event(json):print('received json: ' + str(json))
復制代碼

自定義命名事件也可以支持多個參數:

@socketio.on('my event')
def handle_my_custom_event(arg1, arg2, arg3):print('received args: ' + arg1 + arg2 + arg3)
復制代碼

Flask-SocketIO 支持 SocketIO 命名空間,允許客戶端在同一物理套接字上復用多個獨立連接:

@socketio.on('my event', namespace='/test')
def handle_my_custom_namespace_event(json):print('received json: ' + str(json))
復制代碼

如果未指定名稱空間,'/'則使用具有名稱的默認全局名稱空間 。

對于裝飾器語法不方便的情況,on_event可以使用該方法:

def my_function_handler(data):passsocketio.on_event('my event', my_function_handler, namespace='/test')
復制代碼

客戶端可以請求確認回叫,確認收到他們發送的消息。處理函數返回的任何值都將作為回調函數中的參數傳遞給客戶端:

@socketio.on('my event')
def handle_my_custom_event(json):print('received json: ' + str(json))return 'one', 2
復制代碼

在上面的示例中,將使用兩個參數調用客戶端回調函數,'one'2。如果處理程序函數未返回任何值,則將調用客戶端回調函數而不帶參數。

發送消息

如上一節所示定義的 SocketIO 事件處理程序可以使用send()emit() 函數將回復消息發送到連接的客戶端。

以下示例將收到的事件退回給發送它們的客戶端:

from flask_socketio import send, emit@socketio.on('message')
def handle_message(message):send(message)@socketio.on('json')
def handle_json(json):send(json, json=True)@socketio.on('my event')
def handle_my_custom_event(json):emit('my response', json)
復制代碼

注意如何send()emit()分別用于無名和命名事件。

當有命名空間的工作,send()emit()默認使用傳入消息的命名空間。可以使用可選namespace參數指定不同的命名空間:

@socketio.on('message')
def handle_message(message):send(message, namespace='/chat')@socketio.on('my event')
def handle_my_custom_event(json):emit('my response', json, namespace='/chat')
復制代碼

要發送具有多個參數的事件,請發送元組:

@socketio.on('my event')
def handle_my_custom_event(json):emit('my response', ('foo', 'bar', json), namespace='/chat')
復制代碼

SocketIO 支持確認回調,確認客戶端收到了一條消息:

def ack():print 'message was received!'@socketio.on('my event')
def handle_my_custom_event(json):emit('my response', json, callback=ack)
復制代碼

使用回調時,Javascript 客戶端會收到一個回調函數,以便在收到消息時調用。客戶端應用程序調用回調函數后,服務器將調用相應的服務器端回調。如果使用參數調用客戶端回調,則這些回調也作為服務器端回調的參數提供。

廣播

SocketIO 的另一個非常有用的功能是廣播消息。SocketIO 支持通過此功能broadcast=True可選參數send()emit()

@socketio.on('my event')
def handle_my_custom_event(data):emit('my response', data, broadcast=True)
復制代碼

在啟用廣播選項的情況下發送消息時,連接到命名空間的所有客戶端都會接收它,包括發件人。如果未使用名稱空間,則連接到全局名稱空間的客戶端將收到該消息。請注意,不會為廣播消息調用回調。

在此處顯示的所有示例中,服務器響應客戶端發送的事件。但對于某些應用程序,服務器需要是消息的發起者。這對于向客戶端發送通知在服務器中的事件(例如在后臺線程中)非常有用。socketio.send()socketio.emit()方法可用于廣播到所有連接的客戶端:

def some_function():socketio.emit('some event', {'data': 42})
復制代碼

請注意,socketio.send()socketio.emit()在上下文理解上和send()emit()功能不同。另請注意,在上面的用法中沒有客戶端上下文,因此broadcast=True是默認的,不需要指定。

房間

對于許多應用程序,有必要將用戶分組為可以一起尋址的子集。最好的例子是具有多個房間的聊天應用程序,其中用戶從他們所在的房間接收消息,而不是從其他用戶所在的其他房間接收消息。SocketIO 支持通過房間的概念join_room()leave_room()功能:

from flask_socketio import join_room, leave_room@socketio.on('join')
def on_join(data):username = data['username']room = data['room']join_room(room)send(username + ' has entered the room.', room=room)@socketio.on('leave')
def on_leave(data):username = data['username']room = data['room']leave_room(room)send(username + ' has left the room.', room=room)
復制代碼

send()emit()函數接受一個可選room導致被發送到所有的都在定房客戶端的消息的說法。

所有客戶端在連接時都會被分配一個房間,以連接的會話ID命名,可以從中獲取request.sid。給定的客戶可以加入任何房間,可以給出任何名稱。當客戶端斷開連接時,它將從其所在的所有房間中刪除。無上下文socketio.send()socketio.emit()函數也接受一個room參數,以廣播給房間中的所有客戶端。

由于為所有客戶端分配了個人房間,為了向單個客戶端發送消息,客戶端的會話 ID 可以用作房間參數。

錯誤處理

Flask-SocketIO還可以處理異常:

@socketio.on_error()        # Handles the default namespace
def error_handler(e):pass@socketio.on_error('/chat') # handles the '/chat' namespace
def error_handler_chat(e):pass@socketio.on_error_default  # handles all namespaces without an explicit error handler
def default_error_handler(e):pass
復制代碼

錯誤處理函數將異常對象作為參數。

還可以使用request.event變量檢查當前請求的消息和數據參數,這對于事件處理程序外部的錯誤記錄和調試很有用:

from flask import request@socketio.on("my error event")
def on_my_event(data):raise RuntimeError()@socketio.on_error_default
def default_error_handler(e):print(request.event["message"]) # "my error event"print(request.event["args"])    # (data,)
復制代碼

基于類的命名空間

作為上述基于裝飾器的事件處理程序的替代,屬于命名空間的事件處理程序可以創建為類的方法。flask_socketio.Namespace作為基類提供,用于創建基于類的命名空間:

from flask_socketio import Namespace, emitclass MyCustomNamespace(Namespace):def on_connect(self):passdef on_disconnect(self):passdef on_my_event(self, data):emit('my_response', data)socketio.on_namespace(MyCustomNamespace('/test'))
復制代碼

使用基于類的命名空間時,服務器接收的任何事件都將調度到名為帶有on_前綴的事件名稱的方法。例如,事件my_event將由名為的方法處理on_my_event。如果收到的事件沒有在命名空間類中定義的相應方法,則忽略該事件。基于類的命名空間中使用的所有事件名稱必須使用方法名稱中合法的字符。

為了方便在基于類的命名空間中定義的方法,命名空間實例包括類中的幾個方法的版本,flask_socketio.SocketIOnamespace沒有給出參數時,這些方法 默認為正確的命名空間。

如果事件在基于類的命名空間中具有處理程序,并且還有基于裝飾器的函數處理程序,則僅調用修飾的函數處理程序。

測試

以上是作為官網文檔的翻譯,下面來說說寫完了代碼之后,應該怎么來調試。

<script type="text/javascript" src="//cdnjs.cloudflare.com/ajax/libs/socket.io/1.3.6/socket.io.min.js"></script>
<script type="text/javascript" charset="utf-8">var socket = io.connect('http://' + document.domain + ':' + location.port);socket.on('connect', function() {socket.emit('my event', {data: 'I\'m connected!'});});
</script>
復制代碼

使用 JavaScript 來連接服務端,這里說一個我遇到的問題,最開始使用的是 jsbin 來測試,但怎么都連不到后端,原因就是 jsbin 是 HTTPS 的,而我的請求是 HTTP,于是還是老老實實寫了一個 HTML 文件,源碼可以直接在 Github 下載。

<!DOCTYPE HTML>
<html>
<head><title>Flask-SocketIO Test</title><script type="text/javascript" src="//code.jquery.com/jquery-1.4.2.min.js"></script><script type="text/javascript" src="//cdnjs.cloudflare.com/ajax/libs/socket.io/1.3.5/socket.io.min.js"></script><script type="text/javascript" charset="utf-8">$(document).ready(function() {namespace = '/test';var socket = io.connect(location.protocol + '//' + document.domain + ':' + location.port + namespace);socket.on('connect', function() {socket.emit('my_event', {data: 'I\'m connected!'});});socket.on('my_response', function(msg) {$('#log').append('<br>' + $('<div/>').text('Received #' + msg.count + ': ' + msg.data).html());});$('form#emit').submit(function(event) {socket.emit('my_event', {data: $('#emit_data').val()});return false;});});</script>
</head>
<body><h1>Flask-SocketIO Test</h1><p>Async mode is: <b>{{ async_mode }}</b></p><h2>Send:</h2><form id="emit" method="POST" action='#'><input type="text" name="emit_data" id="emit_data" placeholder="Message"><input type="submit" value="Echo"></form><h2>Receive:</h2><div id="log"></div>
</body>
</html>
復制代碼

有了這個頁面之后,就可以直接在瀏覽器中輸入 http://127.0.0.1:5000 訪問服務端了,更多功能可以隨意折騰。



相關文檔:

github.com/miguelgrinb…

flask-socketio.readthedocs.io/en/latest/

windrocblog.sinaapp.com/?p=1628

zhuanlan.zhihu.com/p/31118736

letus.club/2016/04/10/…

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/389340.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/389340.shtml
英文地址,請注明出處:http://en.pswp.cn/news/389340.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

STL-開篇

基本概念 STL&#xff1a; Standard Template Library&#xff0c;標準模板庫 定義&#xff1a; c引入的一個標準類庫 特點&#xff1a;1&#xff09;數據結構和算法的 c實現&#xff08; 采用模板類和模板函數&#xff09;2&#xff09;數據的存儲和算法的分離3&#xff09;高…

Symbol Mc1000 聲音的設置以及播放

首先引用Symbol.Audio 加一命名空間using Symbol.Audio; /聲音設備的設置 //Select Device from device list Symbol.Audio.Device MyDevice (Symbol.Audio.Device)Symbol.StandardForms.SelectDevice.Select( Symbol.Audio.Controller.Title, Symbol.Audio.Devic…

/bin/bash^M: 壞的解釋器: 沒有那個文件或目錄

在win下編輯的時候&#xff0c;換行結尾是\n\r &#xff0c; 而在linux下 是\n&#xff0c;所以會多出來一個\r&#xff0c;這樣會出現錯誤 此時執行 sed -i s/\r$// file.sh 將file.sh中的\r都替換為空白&#xff0c;問題解決轉載于:https://www.cnblogs.com/zzdbullet/p/9890…

rcp rapido_為什么氣流非常適合Rapido

rcp rapidoBack in 2019, when we were building our data platform, we started building the data platform with Hadoop 2.8 and Apache Hive, managing our own HDFS. The need for managing workflows whether it’s data pipelines, i.e. ETL’s, machine learning predi…

pandas處理丟失數據與數據導入導出

3.4pandas處理丟失數據 頭文件&#xff1a; import numpy as np import pandas as pd丟棄數據部分&#xff1a; dates pd.date_range(20130101,periods6) df pd.DataFrame(np.random.randn(6,4),indexdates,columns[A,B,C,D]) df.iloc[0,1] np.nan df.iloc[1,2] np.nanp…

Mysql5.7開啟遠程

2019獨角獸企業重金招聘Python工程師標準>>> 1.注掉bind-address #bind-address 127.0.0.1 2.開啟遠程訪問權限 grant all privileges on *.* to root"xxx.xxx.xxx.xxx" identified by "密碼"; 或 grant all privileges on *.* to root"%…

分類結果可視化python_可視化分類結果的另一種方法

分類結果可視化pythonI love good data visualizations. Back in the days when I did my PhD in particle physics, I was stunned by the histograms my colleagues built and how much information was accumulated in one single plot.我喜歡出色的數據可視化。 早在我獲得…

算法組合 優化算法_算法交易簡化了風險價值和投資組合優化

算法組合 優化算法Photo by Markus Spiske (left) and Jamie Street (right) on UnsplashMarkus Spiske (左)和Jamie Street(右)在Unsplash上的照片 In the last post, we saw how actual algorithms are developed and tested. In this post, we will figure out the level of…

Symbol Mc1000 快捷鍵 的 設置 事件 開發

switch (e.KeyCode) { ///數據 case Keys.F1://清除數據 if(File.Exists("Storage Card/CG.sdf")) { Mc.gConn.Close(); Mc.gConn.Dispose(); File.Delete("Storage Card/CG.sdf"); } MessageBox.S…

pandas合并concatmerge和plot畫圖

3.6&#xff0c;3.7pandas合并concat&merge 頭文件&#xff1a; import pandas as pd import numpy as npconcat基礎合并用法 df1 pd.DataFrame(np.ones((3,4))*0,columns [a,b,c,d]) df2 pd.DataFrame(np.ones((3,4))*1,columns [a,b,c,d]) df3 pd.DataFrame(np.ones…

Android跳轉WIFI界面的四種方式

第一種 Intent intent new Intent(); intent.setAction("android.net.wifi.PICK_WIFI_NETWORK"); startActivity(intent); 第二種 startActivity(new Intent(android.provider.Settings.ACTION_WIFI_SETTINGS)); 第三種 Intent i new Intent(); if(android.os.Buil…

PS摳發絲技巧 「選擇并遮住…」

PS摳發絲技巧 「選擇并遮住…」 現在的海報設計&#xff0c;大多數都有模特MM&#xff0c;然而MM的頭發實用太多了&#xff0c;有的還飄起來…… 對于設計師(特別是淘寶美工)沒有一個強大、快速、實用的摳發絲技巧真的混不去哦。而PS CC 2017版本開始&#xff0c;就有了一個強大…

covid 19如何重塑美國科技公司的工作文化

未來 &#xff0c; 技術 &#xff0c; 觀點 (Future, Technology, Opinion) Who would have thought that a single virus would take down the whole world and make us stay inside our homes? A pandemic wave that has altered our lives in such a way that no human (bi…

Symbol Mc1000 Text文本閱讀器整體代碼

using System; using System.ComponentModel;using System.Data;using System.Drawing;using System.Text;using System.Windows.Forms;using System.Collections;using System.IO;namespace text{ /// <summary> /// Form1 的摘要說明。 /// </summary> public c…

python生日悖論分析_生日悖論

python生日悖論分析If you have a group of people in a room, how many do you need to for it to be more likely than not, that two or more will have the same birthday?如果您在一個房間里有一群人&#xff0c;那么您需要多少個才能使兩個或兩個以上的人有相同的生日&a…

統計0-n數字中出現k的次數

/*** 統計0-n數字中出現k的次數&#xff0c;其中k范圍為0-9 */ public static int countOne(int k, int n) {if (k > n) {return 0;}int sum 0;int right 0;for (int i 0; n > 0; i) {int last n % 10;sum last * i * (int) Math.pow(10, i - 1);if (k 0) {sum - (…

房價預測 search Search 中對數據預處理的學習

對于缺失的數據&#xff1a; 我們對連續數值的特征做標準化&#xff08;standardization&#xff09;&#xff1a;設該特征在整個數據集上的均值為 μ &#xff0c;標準差為 σ 。那么&#xff0c;我們可以將該特征的每個值先減去 μ 再除以 σ 得到標準化后的每個特征值。對于…

3.6.1.非阻塞IO

本節講解什么是非阻塞IO&#xff0c;如何將文件描述符修改為非阻塞式 3.6.1.1、阻塞與非阻塞 &#xff08;1&#xff09;阻塞是指函數調用會被阻塞。本質是當前進程調用了函數&#xff0c;進入內核里面去后&#xff0c;因為當前進程的執行條件不滿足&#xff0c;內核無法里面完…

rstudio 管道符號_R中的管道指南

rstudio 管道符號R基礎知識 (R Fundamentals) Data analysis often involves many steps. A typical journey from raw data to results might involve filtering cases, transforming values, summarising data, and then running a statistical test. But how can we link al…