[转]Implement a WebSocket Using Flask and Socket-IO(Python) 使用Python Flask实现Socket

实验成功,值得学习。所以记录在文章中,学习研究。

=============================================

Learn how to compose the client-server interface utilizing Websocket technology with Flask and Socket-IO modules available in python

=============================================

使用以下文章中的内容时候,如果遇见了 The client is using an unsupported version of the Socket.IO or Engine.IO protocols Error 这个错误,那就是引用的版本问题。参考文档:https://stackoverflow.com/questions/66069215/the-client-is-using-an-unsupported-version-of-the-socket-io-or-engine-io-protoco 来解决。

The client is using an unsupported version of the Socket.IO or Engine.IO protocols (further occurrences of this error will be logged with level INFO)
192.168.1.80 - - [05/Feb/2021 18:30:41] "GET /socket.io/?EIO=3&transport=polling&t=NTpTT-L HTTP/1.1" 400 219 0.000618
 
There appears to be some backward compatibility issues with SocketIO. You can uninstall python-engineiopython-socketio (and Flask-SocketIO just to be on the safe side) and reinstall lower versions.

The combination that worked for me was:

Flask-SocketIO==4.3.1
python-engineio==3.13.2
python-socketio==4.6.0

 

To fix the version incompatibility, you can run below "upgrade"commands in VS Code

python -m pip install --upgrade python-socketio==4.6.0

python -m pip install --upgrade python-engineio==3.13.2

python -m pip install --upgrade Flask-SocketIO==4.3.1

 

=============================================

 

HTTP carries extra overheard in individual request and response, WebSocket carries the overhead data while placing connection then it carries less or balanced data within individual request-response.

 
Difference HTTP vs WebSocket

Note: For full-duplex Bi-directional client-server communication the WebSocket is the best choice.

The WebSocket’s can be implemented with all server-side technologies, I am using Flask and Socket-IO modules from Python.
Please understand the steps below to implement the WebSocket using Flask and Socket-IO

 

Step1: Creating a project and creating requirements.txt

  • First of all, will start by setting up the virtual environment for our sample project.
  1. Create a project folder.
  2. Create a requirments.txt file into the project folder.
  3. Add below code into requirments.txt.
Flask==1.0.2
Flask-Login==0.4.1
Flask-Session==0.3.1
Flask_SocketIO
itsdangerous==1.1.0
Jinja2==2.10
MarkupSafe==1.1.0
python-engineio
python-socketio
six==1.11.0
Werkzeug==0.14.1

 

Note: the above dependency is required for implementing a web socket so we will install all for creating the virtual environment.

Step2: Creating a virtual environment and install all required modules from python.

  • Now create a virtual environment “VENV” for the project.
 
create a virtual environment
  • Go to project root folder and open terminal/cmd and execute the below commands

$ virtualenv <envname>:

envname” can be anything I have used “websocketenv”

  • Activate the virtual env now(Execute the activate.bat file present location)

$ {Project Root path}/websocketenv/Scripts/activate.bat

  • Now install the requirements.txt using the command

$ pip install requirements.txt

The current project structure looks like this. for me.

 
Current project structure
 

Step3: We will design a simple program for understanding the functionality of a WebSocket.

  • Create a Python file named app.py in the project root folder.
  • Add the below code into the app.py

Note: First We are creating a client GUI web page for implementing the WebSocket basic feature of a running WebSocket.

app.py

from flask import Flask, render_template
from flask_socketio import SocketIO
async_mode = None
app = Flask(__name__)
socket_ = SocketIO(app, async_mode=async_mode)@app.route('/')
def index():
    return render_template('index.html',
                           sync_mode=socket_.async_mode)


if __name__ == '__main__':
    socket_.run(app, debug=True)

 

  • Now create the templates directory into the project root folder and create one index.html file in the templates directory.
  • Add the below code into index.html

index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>WebSocket</title>
</head>
<body>
<h1>This is webSocket client</h1>
</body>
</html>

 

Now we can test the WebSocket by running “app.py”

The expected console output will be after running app.py

 
WebSocket console output

Now run the URL: http://localhost:5000/ into a web browser and you will see the message “This is WebSocket Client” on the web page.

**127.0.0.1 — — [2020–08–17 10:09:07] “GET / HTTP/1.1” 200 260 0.004024**

If the WebSocket connection is established then the above request log will be added in the console logs whenever the web page will get refreshed.

Flask, render_template
flask_socketio , SocketIO

we have used the following modules for implementing the basic socket but it is not showcasing anything like how socket works so, let’s extend the feature and implement the sending message and receiving from one client to another.

 

Final Step: We will implement a message passing from one client to another client in this step.

The current project structure is like this:

Current Project structure

The final code for app.py and index.html

app.py

from flask import Flask, render_template, session, copy_current_request_context
from flask_socketio import SocketIO, emit, disconnect
from threading import Lock


async_mode = None
app = Flask(__name__)
app.config['SECRET_KEY'] = 'secret!'
socket_ = SocketIO(app, async_mode=async_mode)
thread = None
thread_lock = Lock()


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


@socket_.on('my_event', namespace='/test')
def test_message(message):
    session['receive_count'] = session.get('receive_count', 0) + 1
    emit('my_response',
         {'data': message['data'], 'count': session['receive_count']})


@socket_.on('my_broadcast_event', namespace='/test')
def test_broadcast_message(message):
    session['receive_count'] = session.get('receive_count', 0) + 1
    emit('my_response',
         {'data': message['data'], 'count': session['receive_count']},
         broadcast=True)


@socket_.on('disconnect_request', namespace='/test')
def disconnect_request():
    @copy_current_request_context
    def can_disconnect():
        disconnect()

    session['receive_count'] = session.get('receive_count', 0) + 1
    emit('my_response',
         {'data': 'Disconnected!', 'count': session['receive_count']},
         callback=can_disconnect)


if __name__ == '__main__':
    socket_.run(app, debug=True)

 

index.html

<!DOCTYPE HTML>
<html>
<head>
    <title>Socket-Test</title>
    <script src="//code.jquery.com/jquery-1.12.4.min.js"></script>
    <script src="//cdnjs.cloudflare.com/ajax/libs/socket.io/2.2.0/socket.io.js"></script>
    <script type="text/javascript" charset="utf-8">
        $(document).ready(function() {

            namespace = '/test';
            var socket = io(namespace);

            socket.on('connect', function() {
                socket.emit('my_event', {data: 'connected to the SocketServer...'});
            });

            socket.on('my_response', function(msg, cb) {
                $('#log').append('<br>' + $('<div/>').text('logs #' + msg.count + ': ' + msg.data).html());
                if (cb)
                    cb();
            });
            $('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;
            });
            $('form#disconnect').submit(function(event) {
                socket.emit('disconnect_request');
                return false;
            });
        });
    </script>
</head>
<body style="">

    <h1 style="">Socket</h1>
    <form id="emit" method="POST" action='#'>
        <input type="text" name="emit_data" id="emit_data" placeholder="Message">
        <input type="submit" value="Send Message">
    </form>
    <form id="broadcast" method="POST" action='#'>
        <input type="text" name="broadcast_data" id="broadcast_data" placeholder="Message">
        <input type="submit" value="Send Broadcast Message">
    </form>

    <form id="disconnect" method="POST" action="#">
        <input type="submit" value="Disconnect Server">
    </form>
    <h2 style="">Logs</h2>
    <div id="log" ></div>
</body>
</html>

 

After adding the final code please start the WebSocket server by running app.py and now again we can check the output in the web browser.

 
Output web page socket server
  • Here we have implemented two kinds of message one is “Send Message” that’s is a normal ping msg and Send Broadcast Message which is sending or broadcasting the data over a socket connection.
  • We have a couple of options to check the functionality but if we run socket on localhost then it's difficult to observe the feature.

 

 

We can use the “NGROK” tool and we can easily make localhost servers accessible anywhere.

One the localhost is set up according to the above link, you can use the generated HTTP or HTTPs URLs instead of the localhost and You can test a Socket server like a live hosted server and use it as a simple chat broadcast server.

Can open the link into your phone and see the message sharing in between. Or use another computer and test exchanging messages.

Please explore the code one by one and here I have given some explanations about few must-know things from source code.

async_mode = None
app = Flask(__name__)
socket_ = SocketIO(app, async_mode=async_mode)

we were given the Flask app instance (standard initialization)
we were not given the app, but we were given a message_queue (standard initialization for the auxiliary process), will call init_app from an app factory function.

@app.route('/')

A decorator that is used to register a view function for a given URL rule.

@socketio.on('my event', namespace='/chat')

A Decorator to register a SocketIO event handler. This decorator must be applied to SocketIO event handlers.

This small application can be extended for any features please do have use of it freely.

Thanks, Programmers

Happy Coding!

 

[Source: https://medium.com/swlh/implement-a-websocket-using-flask-and-socket-io-python-76afa5bbeae1]

 

 

 

posted @ 2021-11-01 20:58  路边两盏灯  阅读(577)  评论(3编辑  收藏  举报