This is the 23rd day of my participation in the August More Text Challenge.More challenges in August

Hardware and software Environment

  • windows 10 64bit
  • Anaconda3 with python 3.7
  • Pycharm 2020.1.2
  • Flask 1.1.2
  • Flask – socketio 4.3.1

What is the websocket

WebSocket is a network communication protocol. Different from HTTP, WebSocket provides full-duplex communication. That is to say, in the traditional way, only when the client initiates a request, the server will send data, but WebSocket can let the server actively send data to the client, it is a server push technology.

The following figure shows the difference between WebSocket and HTTP

websocketd

Websocketd is a very good WebSocket server, we first use it to understand the standard WebSocket interaction. Download the Windows version of WebSocketd, unpack it, and go to the directory

Now write a test script in Python named test.py that periodically prints a value to the standard output stdout

From sys import stdout from time import sleep for count in range(0, 10): print(count + 1) stdout.flush() sleep(0.5)Copy the code

Open the service

websocketd --port 8080 python test.py
Copy the code

Now need a WebSocket client, we came to the chrome store, installing a plug-in chrome.google.com/webstore/de… “, and then open the plugin, enter the URL of the WebSocket to see the output on the server side

flask-socketio

Flask-socketio enables Flask applications to access low-latency two-way communication between clients and servers. Client applications can use Javascript, C++, Java, and any SocketIO official client library in Swift or any compatible client to establish a permanent connection to the server.

Asynchronous mode

Flask-socketio requires the support of low-level asynchronous services. It is flexible enough to detect asynchronous services in the current environment in the order of eventlet > gEvent > Werkzeug

  • eventletBest performance, support long polling andWebSockettransmission
  • geventSupported in many different configurations.geventFull support for long polling transfer, but witheventletDifferent,geventNot the nativeWebSocketSupport. To add toWebSocketThe support currently has two options: installgevent-websocketPackage forgeventincreaseWebSocketSupport, or you can use withWebSocketThe function ofuWSGI WebThe server.geventThe use of is also a high performance option, but slightly lesseventlet
  • werkzeugCan also be used based onwerkzeugtheFlaskDevelopment server, however, it is important to note that it lacks the performance of the other two options, so it is only suitable for simple development environments, and it only supports long polling transport

The installation

Use PIP directly to install

pip install eventlet
pip install flask-socketio
Copy the code

The sample code

Look at the server-side code first

File run. Py

from flask import Flask, render_template from flask_socketio import SocketIO, emit app = Flask(__name__) app.config['SECRET_KEY'] = 'secret_key' socketio = SocketIO() socketio.init_app(app, cors_allowed_origins='*') name_space = '/dcenter' @app.route('/') def index(): return render_template('index.html') @app.route('/push') def push_once(): event_name = 'dcenter' broadcasted_data = {'data': "test message!" } socketio.emit(event_name, broadcasted_data, broadcast=False, namespace=name_space) return 'done! ' @socketio.on('connect', namespace=name_space) def connected_msg(): print('client connected.') @socketio.on('disconnect', namespace=name_space) def disconnect_msg(): print('client disconnected.') @socketio.on('my_event', namespace=name_space) def mtest_message(message): print(message) emit('my_response', {'data': message['data'], 'count': 1}) if __name__ == '__main__': = '0.0.0.0 socketio. Run (app, the host', the port = 5000, debug = True)Copy the code

In the code, we set up the namespace, because the url that the client needs to connect contains namespace, and there is also the concept of event, connect, disconnect and custom my_event

The code for the index.html file is as follows

<! DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>SocketIO Demo</title> <script type="text/javascript" SRC = "/ / cdn.bootcss.com/jquery/3.1.1/jquery.min.js" > < / script > < script type = "text/javascript" SRC = "/ / cdn.bootcss.com/socket.io/1.5.1/socket.io.min.js" > < / script > < / head > < body > < h2 > Demo of SocketIO < / h2 > < div id="t"></div> <script> $(document).ready(function () { namespace = '/dcenter'; var socket = io.connect(location.protocol + '//' + document.domain + ':' + location.port + namespace); socket.on('dcenter', function (res) { var t = res.data; if (t) { $("#t").append(t).append('<br/>'); }}); }); </script> </body> </html>Copy the code

After starting the service, we go to http://127.0.0.1:5000 and leave the page untouched because it will display the messages we receive later

At that time, use the browser to http://127.0.0.1:5000/push

We use this method to trigger the server to send a message to the client, and go back to the previous page to see that the message sent from the server is displayed on the page

Note that in the javascript above, the PROTOCOL used in the URL is HTTP, not WS, which is a bit different from the native WebSocket.

Cors cross-domain error

If the front and back ends are separated, the following error occurs

Traceback (most recent call last): File "src\gevent\greenlet.py", line 854, in gevent._gevent_cgreenlet.Greenlet.run File "C:\ProgramData\Anaconda3\envs\FlaskTutorial\lib\site-packages\gevent\baseserver.py", line 34, in _handle_and_close_when_done return handle(*args_tuple) File "C:\ProgramData\Anaconda3\envs\FlaskTutorial\lib\site-packages\gevent\server.py", line 233, in wrap_socket_and_handle with _closing_socket(self.wrap_socket(client_socket, **self.ssl_args)) as ssl_socket: TypeError: wrap_socket() got an unexpected keyword argument 'cors_allowed_origins' 2020-09-09T08:16:07Z <Greenlet at 0x1812f1e8bf8:  _handle_and_close_when_done(<bound method StreamServer.wrap_socket_and_handle , <bound method StreamServer.do_close of <WSGIServer, (<gevent._socket3.socket [closed] at 0x1812fc41cc8)> failed with TypeErrorCopy the code

This is a cross-domain problem. After testing, we found that using flask-CORS, which was introduced earlier, does not work. We need to add the necessary parameters during socketio initialization

socketio = SocketIO()
socketio.init_app(app, cors_allowed_origins='*')
Copy the code

Detailed information can be found at github.com/eventlet/ev…

Download the source code

Github.com/xugaoxiang/…

Flask Series of Tutorials

For more Flask tutorials, go ahead

Xugaoxiang.com/category/py…

The resources

  • websocketd.com/
  • Github.com/miguelgrinb…
  • flask-socketio.readthedocs.io/en/latest/
  • Stackoverflow.com/questions/6…
  • Zh.wikipedia.org/wiki/Socket…
  • Juejin. Im/post / 684490…
  • Github.com/miguelgrinb…
  • Github.com/miguelgrinb…