“Easy WebSockets with Flask and Gevent” 翻譯學習筆記 ——Flask WebSocket使用快速入門

来源:http://www.cnblogs.com/KattyJoy/archive/2016/08/16/5777356.html
-Advertisement-
Play Games

原文鏈接:http://blog.miguelgrinberg.com/post/easy-websockets-with-flask-and-gevent 介紹部分就先不翻了 This weekend I decided to take a short vacation from my book ...


原文鏈接:http://blog.miguelgrinberg.com/post/easy-websockets-with-flask-and-gevent

介紹部分就先不翻了

This weekend I decided to take a short vacation from my book writing effort and spend time on a project I wanted to work on for a long time. The result of this effort is a brand new Flask extension that I think is pretty cool.

I'm happy to introduce Flask-SocketIO, a very easy to use extension that enables WebSocket communications in Flask applications.

What is WebSocket?

WebSocket is a new communication protocol introduced with HTML5, mainly to be implemented by web clients and servers, though it can also be implemented outside of the web.

Unlike HTTP connections, a WebSocket connection is a permanent, bi-directional communication channel between a client and the server, where either one can initiate an exchange. Once established, the connection remains available until one of the parties disconnects from it.

WebSocket connections are useful for games or web sites that need to display live information with very low latency. Before this protocol existed there were other much less efficient approaches to achieve the same result such as Comet.

The following web browsers support the WebSocket protocol:

  • Chrome 14
  • Safari 6
  • Firefox 6
  • Internet Explorer 10

What is SocketIO?

SocketIO is a cross-browser Javascript library that abstracts the client application from the actual transport protocol. For modern browsers the WebSocket protocol is used, but for older browsers that don't have WebSocket SocketIO emulates the connection using one of the older solutions, the best one available for each given client.

The important fact is that in all cases the application uses the same interface, the different transport mechanisms are abstracted behind a common API, so using SocketIO you can be pretty much sure that any browser out there will be able to connect to your application, and that for every browser the most efficient method available will be used.

What about Flask-Sockets?

A while ago Kenneth Reitz published Flask-Sockets, another extension for Flask that makes the use of WebSocket accessible to Flask applications.

The main difference between Flask-Sockets and Flask-SocketIO is that the former wraps the native WebSocket protocol (through the use of the gevent-websocket project), so it can only be used by the most modern browsers that have native support. Flask-SocketIO transparently downgrades itself for older browsers.

Another difference is that Flask-SocketIO implements the message passing protocol exposed by the SocketIO Javascript library. Flask-Sockets just implements the communication channel, what is sent on it is entirely up to the application.

Flask-SocketIO also creates an environment for event handlers that is close to that of regular view functions, including the creation of application and request contexts. There are some important exceptions to this explained in the documentation, however.


 

A Flask-SocketIO Server

Flask-SocketIO 伺服器端代碼

Installation of Flask-SocketIO is very simple:

使用pip安裝Flask-SocketIO

$ pip install flask-socketio

 

Note that Flask-SocketIO depends on gevent, so at this time it can only run on Python 2.x. Support for Python 3 is coming for gevent, so the situation is likely to improve in the near future. (Update: Flask-SocketIO version 1.0 is fully compatible with Python 2.7 and 3.3+, see bottom of the article for more information).

目前的最新狀態是,Flask-SocketIO版本v1.0 可以運行在Python 2.7和 Python 3.3+上

 

Below is an example Flask application that implements Flask-SocketIO:

以下是一個實現了Flask-SocketIO的簡單Flask應用程式

from flask import Flask, render_template
from flask.ext.socketio import SocketIO, emit

app = Flask(__name__)
app.config['SECRET_KEY'] = 'secret!'
socketio = SocketIO(app)

@app.route('/')
def index():
    return render_template('index.html')

@socketio.on('my event', namespace='/test')
def test_message(message):
    emit('my response', {'data': message['data']})

@socketio.on('my broadcast event', namespace='/test')
def test_message(message):
    emit('my response', {'data': message['data']}, broadcast=True)

@socketio.on('connect', namespace='/test')
def test_connect():
    emit('my response', {'data': 'Connected'})

@socketio.on('disconnect', namespace='/test')
def test_disconnect():
    print('Client disconnected')

if __name__ == '__main__':
    socketio.run(app)

  

The extension is initialized in the usual way, but to simplify the start up of the server a customrun() method is provided by the extension. This method starts gevent, the only supported web server. Using gunicorn with a gevent worker should also work. The run() method takes optionalhost and port arguments, but by default it will listen on localhost:5000 like Flask's development web server. 拓展(即socketio)的初始化方式與一般的初始化一樣(即 socketio = SocketIO(app) ),在SocketIO的程式里,通過調用成員函數run()來啟動伺服器(即 socketio.run(app) ),該方法啟動了gevent(Python里一個提供併發支持的模塊,通過管理切換greelet實現的協程來實現併發)。使用gunicorn和gevent worker也可以。run()函數有可選參數hostargument等,預設按Flask實現的伺服器一樣,監聽localhost:5000  

The only traditional route in this application is /, which serves index.html, a web document that contains the client implementation of this example.

To receive WebSocket messages from the client the application defines event handlers using thesocketio.on decorator.

The first argument to the decorator is the event name. Event names 'connect''disconnect','message' and 'json' are special events generated by SocketIO. Any other event names are considered custom events.

The 'connect' and 'disconnect' events are self-explanatory. The 'message' event delivers a payload of type string, and the 'json' and custom events deliver a JSON payload, in the form of a Python dictionary.

在上文代碼中,該應用的路由只有/,訪問時返回網頁index.html,包括了該例子中的客戶端實現代碼

修飾符的第一個參數是事件名'connect''disconnect', 'message''json' 等特殊事件名是由SocketIO規定的事件,其他的事件名是自定義事件。

'connect'  'disconnect'事件不必多說,'message' 事件發送一段字元串類型的內容,'json' 事件和自定義事件發送一段JSON內容,形式為Python的dictionary類型

 

Events can be defined inside a namespace by adding the namespace optional argument to thesocketio.on decorator. Namespaces allow a client to open multiple connections to the server that are multiplexed on a single socket. When a namespace is not specified the events are attached to the default global namespace.

通過在socketio.on修飾符中增加namespace可選參數,可以在一個命名空間內定義一個事件。命名空間允許一個客戶端在一個socket連接上多路復用打開多個與伺服器的鏈接。當一個事件沒有指明命名空間,則事件關聯到預設的全局命名空間中。

 

To send events a Flask server can use the send() and emit() functions provided by Flask-SocketIO. The send() function sends a standard message of string or JSON type to the client. The emit() function sends a message under a custom event name.

Flask-SocketIO提供給Flask伺服器send()emit()兩個函數來發送事件。send()函數發送一個字元串或JSON類型的標準消息給客戶端,emit()函數發送一個在自定義事件名之下的消息給客戶端——例如代碼中的 emit('my response', {'data': message['data']}) 就是發送了一條'my response'事件的消息,消息內容主體為 {'data': message['data']} 

 

Messages are sent to the connected client by default, but when including the broadcast=Trueoptional argument all clients connected to the namespace receive the message.

消息預設發送給已連接(且此時通信的這一)的客戶端,但是如果包括了可選參數及取值broadcast=True,則消息被髮送給所有連接到該名字空間的客戶端

 


 

 

A SocketIO Client

SocketIO 客戶端代碼

Ready to try your hand at some Javascript? The index.html page used by the example server contains a little client application that uses jQuery and SocketIO. The relevant code is shown below:

伺服器端例子中的index.html頁包含了一個使用jQuery和SocketIO的客戶端程式例子,示例代碼網址:https://github.com/miguelgrinberg/Flask-SocketIO/blob/master/example/templates/index.html要使用jQuery和SocketIO需要先引用其js文件,否則會報錯

<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>

相應代碼如下:

$(document).ready(function(){
    var socket = io.connect('http://' + document.domain + ':' + location.port + '/test');
    socket.on('my response', function(msg) {
        $('#log').append('<p>Received: ' + msg.data + '</p>');
    });
    $('form#emit').submit(function(event) {
        socket.emit('my event', {data: $('#emit_data').val()});
        return false;
    });
    $('form#broadcast').submit(function(event) {
        socket.emit('my broadcast event', {data: $('#broadcast_data').val()});
        return false;
    });
});

 

The socket variable is initialized with a SocketIO connection to the server. Note how the namespace /test is specified in the connection URL. To connect without using a namespace it is sufficient to call io.connect() without any arguments.

變數socket的初始化建立了一個和伺服器的SocketIO連接,在連接URL中指定命名空間/test的方式是 io.connect('http://' + document.domain + ':' + location.port + '/test') 。如果要建立連接而不指明命名空間則在調用io.connect()函數時不使用任何參數。

 

The socket.on() syntax is used in the client side to define an event handler. In this example a custom event with name 'my response' is handled by adding the data attribute of the message payload to the contents of a page element with id log. This element is defined in the HTML portion of the page.

客戶端使用的socket.on()定義了一個事件的Handler,本例中對一個自定義的事件'my response'的處理是將消息內容中的data屬性值添加到id為log的頁面元素中。log元素的定義在網頁的HTML部分。

 

The next two blocks override the behavior of two form submit buttons so that instead of submitting a form over HTTP they trigger the execution of a callback function.

For the form with id emit the submit handler emits a message to the server with name 'my event' that includes a JSON payload with a data attribute set to the value of the text field in that form.

The second form, with id broadcast does the same thing, but sends the data under a different event name called 'my broadcast event'.

接下來兩塊重寫了兩個表單提交按鈕的響應內容,不再執行預設的提交HTTP表單,而是觸發了(伺服器端)事件的響應函數。

id為emit的表單的提交handler向伺服器發出了一個名為'my event' 的事件消息,消息內容形式為JSON,包含了一個data屬性,其值被設為表單內文字域的值。

第二個id為broadcast的表單做了類似的事,但是它發送的數據是在事件'my broadcast event'下的。

 

If you now go back to the server code you can review the handlers for these two custom events. For 'my event' the server just echoes the payload back to the client in a message sent under event name 'my response', which is handled by showing the payload in the page. The event named 'my broadcast event' does something similar, but instead of echoing back to the client alone it broadcasts the message to all connected clients, also under the 'my response' event.

此時可以返回伺服器端代碼查看兩個自定義事件對應的handler。對於'my event'事件,伺服器只是把發來的消息原封不動返回給客戶端,消息在事件'my response'之下,這樣會觸發客戶端的'my response'事件,將消息顯示在網頁頁面上;'my broadcast event' 事件的處理過程類似,但是與將消息返回給客戶端不同的是,它將消息廣播給了已連接的客戶端,當然該消息還是在事件'my response'下。

 

You can view the complete HTML document in the GitHub repository.

                                            完整的HTML代碼內容見↗

Running the Example

運行示例

To run this example you first need to download the code from GitHub. For this you have two options:

The example application is in the example directory, so cd to it to begin.

1.首先要從git上clone倉庫,或者下載工程的zip文件,示常式序在example文件夾下

 

To keep your global Python interpreter clean it is a good idea to make a virtual environment:

$ virtualenv venv
$ . venv/bin/activate

2. 為了保證全局Python環境乾凈,最好創建一個虛擬環境(此步可以忽略)

Then you need to install the dependencies:

(venv) $ pip install -r requirements.txt

3.使用pip下載安裝必要的依賴組件↑

 

Finally you can run the application:

(venv) $ python app.py

4.運行伺服器程式↑

 

Now open your web browser and navigate to http://localhost:5000 and you will get a page with two forms as shown in the following screenshot:

 

 

5.打開瀏覽器,訪問http://localhost:5000,查看測試網頁

 

 

Any text you submit from any of the two text fields will be sent to the server over the SocketIO connection, and the server will echo it back to the client, which will append the message to the "Receive" part of the page, where you can already see the message sent by the 'connect' event handler from the server.

Things get much more interesting if you connect a second browser to the application. In my case I'm testing this with Firefox and Chrome, but any two browsers that you run on your machine will do. If you prefer to access the server from multiple machines you can do that too, but you first need to change the start up command to socketio.run(app, host='0.0.0.0') so that the server listens on the public network interface.

With two or more clients when you submit a text from the form on the left only the client that submitted the message gets the echoed response. If you submit from the form on the right the server broadcasts the message to all connected clients, so all get the reply.

If a client disconnects (for example if you close the browser window) the server will detect it a few seconds later and send a disconnect event to the application. The console will print a message to that effect.

Final Words

For a more complete description of this extension please read the documentation. If you want to make improvements to it feel free to fork it and then submit a pull request.

更多完整介紹查看文檔,以下就不翻了

I hope you make cool applications with this extension. I can tell you that I had a lot of fun implementing this extension.

If you make something with it feel free to post links in the comments below.

UPDATE: Flask-SocketIO version 0.3 adds support for rooms. This enables targeting subsets of connected users without having to use the broadcast option that sends to everyone.

UPDATE #2: Flask-SocketIO version 1.0 adds support for Python 3.3+, and offers the choice to use gevent or eventlet as web server, as well as the standard Flask server. When using the Flask server the bi-directional channel is emulated using the HTTP long-polling technique.

Miguel


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • https://framework.zend.com/manual/2.4/en/tutorials/config.advanced.html#environment-specific-system-configuration 有兩個級別的配置:全局和局部也就是系統配置和應用配置。 系統配置:系統配 ...
  • 彙總各路大神寫得ggplot2包文章!http://docs.ggplot2.org/current/ ...
  • 十一、函數 Python中函數以def定義,用於實現某種功能,若是某段代碼被多處使用,不妨將它定義成一個函數,或是它用於實現特定的功能,也可以將它定義成一個函數; 一個函數func(),func為函數名,是這個函數引用(指向函數的地址);而加上括弧func()則表示執行這個函數; 在函數中定義的變數 ...
  • 我的SimpleLoader裡面的一塊 https://github.com/taoshihan1991/simpleloader 效果: ...
  • 程式說明 這是一個十分可靠的程式,這個程式的查錯能力非常強悍。程式包含了文件操作,歸併排序和字元串輸入等多種技術。 程式的功能是從外部讀取一個包括int型數據的文本文件,然後將它保存到內部臨時數組,對數組進行排序後,以文本形式輸出到指定的文件上。因為是int類型的數據,沒有很嚴重的損失精度的問題。 ...
  • 該版本的Activiti運行須知: 1.JDK 6+,Eclipse最好是Kepler以上版本。 2.試驗功能都有EXPERIMENTAL標註,被標註的部分不應該視為穩定的。 有興趣的同學可以去瞭解下Activiti Explorer項目,他涵蓋了大部分Activiti的功能,還沒有Activiti ...
  • 一、手賤行為(✿◡‿◡) 在一次開發中通過xampp方式安裝了PHP環境,需要操作資料庫時通過phpmyadmin訪問MySQL,在一次資料庫操作時想起沒有設置密碼,於是直接在mysql資料庫中的user表中將root用戶的密碼設置為“123456”,關掉頁面,重啟MySQL,再次通過phpmyad ...
  • wxPython ImportError DLL load failed: ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...