2019年1月9日 星期三

[Flask] Socket.IO integration : Flask-SocketIO


 Python   Flask    WebSocket    Socket.IO  



Introduction


We will use Flask-SocketIO on Flask (Server-side) and Socket.IO JS on client to establish WebSocket between them.




Environment

Python 3.6.5
Flask 1.0.2
Flask-SocketIO 3.1.2
Socket.IO 2.2.0


Implement (Server-side)


Install Flask-SocketIO, eventlet

$ pip install flask-socketio
$ pip install eventlet

PS. eventlet supports good performance long-polling and WebSocket transports.

Receive message

Lets create two server-side event handlers:
1.  connected_event
2.  broadcast_event

The first event will be emitted and send a message to the original client when the WebSocket connection between server and the client is established.
The second event is used for broadcasting message to all connected clients with setting broadcast=True.

Inside the two above events, they will both emits the client-side’s server_response event with some data (messages).


main.py

from flask import Flask, request
from flask_socketio import SocketIO, emit

app = Flask(__name__)

# Websocket setting
app.config['SECRET_KEY'] = 'XXXXX'
socketio = SocketIO(app)

@socketio.on('connected_event')
def connected(msg):
    emit('server_response', {'data': msg['data']})

@socketio.on('broadcast_event')
def broadcast(msg):
    emit('server_response', {'data': msg['data']}, broadcast=True)

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



Create a web page
.
Now we are going to create index.html in Flask to interact with the server-side’s events.
The project files’ hierarchy is as following,



We will implement the template: index.html, later.
Now, update main.py to create a new api: index, which will render the template and return the HTML.

main.py

from flask import Flask, render_template, request, jsonify
from flask_socketio import SocketIO, emit
import json

app = Flask(__name__, template_folder='./templates')

# Websocket setting

app.config['SECRET_KEY'] = 'XXXX'
socketio = SocketIO(app)

@app.route('/')
def index():
    return render_template('index.html', async_mode=socketio.async_mode)


# … Skip connected/broadcast SocketIO events



(Optional) Create a web api to emit client-side event

We can implement an web api to emit the event of client-side as following codes.

@app.route('/send', methods=['POST'])
def send():
    jsonobj_content = request.json
    socketio.emit('server_response',  {'data':str(jsonobj_content)}, broadcast=True)
    return '', 200


Notice that use socket.emit() instead of emit() inside a Flask api.

(Request sample in Postman)



Implement (Client-side)


The following steps will be implemented on index.html.


Install/Embed jquery, Socket.IO

For npm users,

$ npm install jquery
$ npm install socket.io-client


I will just use CDN in my sample codes

<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script type="text/javascript" src="//cdnjs.cloudflare.com/ajax/libs/socket.io/1.3.6/socket.io.min.js"></script>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" />


Create connection

$(document).ready(function () {
            var socket = io.connect(); //Or given server url: io.connect("http://xxxx:123")
});



Register event handlers on “connect”


The callback will emits the “connected_event” on server-side

$(document).ready(function () {
            var socket = io.connect(); //Or given server url: io.connect("http://xxxx:123")

            socket.on('connect', function () { //The default event: connect, when a connection is fired
                console.log('Start connect!');
                socket.emit('connected_event', { data: 'I\'m connected!' });
            });
 });



Register event handlers on “server_response”

This handler will receive the message: msg, from server-side and display it.

$(document).ready(function () {
            var socket = io.connect(); //Or given server url: io.connect("http://xxxx:123")

            // … skip connect event handler

socket.on('server_response', function (msg) {
                $('#log').append('<br>' + $('<div/>').text('Received #' + ': ' + msg.data).html());
            });
});

And HTML:

<pre id="log"></pre>



Broadcast message to all connected clients

Implement a Textbox and button to send the message to other clients by emit “broadcast_event”.

$(document).ready(function () {
            var socket = io.connect(); //Or given server url: io.connect("http://xxxx:123")

            // … skip connect event handler
            // … skip server_resposne event handler
  
            $('#emitMsg').on('click', function () {
                var msg = $('#msg').val();
                socket.emit('broadcast_event', { data: msg });
            });           
});


<input type="text"  id="msg" />
<button id="emitMsg">Send Message to all</button>


Demo





To stop the Flask-SocketIO

@app.route('/shutdown', methods=['POST'])
def shutdown():
    socketio.stop()






Sample code






Reference






沒有留言:

張貼留言