Flask-SocketIO Documentation

repository·main·Indexed 26 days ago

https://github.com/miguelgrinberg/flask-socketio

Flask-SocketIO provides Socket.IO integration for Flask applications, enabling real-time, bidirectional communication between clients and servers. It includes support for event handling via decorators, room management, namespaces, and deployment options using embedded servers, Gunicorn, or uWSGI. The library supports scaling via message queues such as Redis, RabbitMQ, and Kafka, and provides a SocketIOTestClient for unit testing.

Tokens
10.4K
Snippets
25
Records
59
Agent score
90%

What's inside Flask-SocketIO

  1. Configure Nginx as a WebSocket Reverse Proxy

    main

    Nginx (version 1.4+) can act as a front-end proxy for HTTP and WebSocket requests. To support scaling with multiple Socket.IO nodes, use the ip_hash directive in an upstream block to ensure 'sticky sessions' (routing a client to the same worker).

    # Load balancing configuration
    upstream socketio_nodes {
        ip_hash;
        server 127.0.0.1:5000;
        server 127.0.0.1:5001;
        server 127.0.0.1:5002;
    }
    
    server {
        listen 80;
        server_name _;
    
        location / {
            include proxy_params;
            proxy_pass http://127.0.0.1:5000;
        }
    
        location /static/ {
            alias <path-to-your-application>/static/;
            expires 30d;
        }
    
        location /socket.io {
            include proxy_params;
            proxy_http_version 1.1;
            proxy_buffering off;
            proxy_set_header Upgrade $http_upgrade;
            proxy_set_header Connection "Upgrade";
            proxy_pass http://socketio_nodes/socket.io;
        }
    }
  2. Set up the Socket.IO client in HTML

    main

    To establish a connection, your application must serve a page that loads the Socket.IO client library and initializes the connection.

    <script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/4.0.1/socket.io.js" integrity="sha512-q/dWJ3kcmjBLU4Qc47E4A9kTB4m3wuTY7vkFJDTZKjTs8jhyGQnaUrxa0Ytd0ssMZhbNua9hE+E7Qv1j+DyZwA==" crossorigin="anonymous"></script>
    <script type="text/javascript" charset="utf-8">
        var socket = io();
        socket.on('connect', function() {
            socket.emit('my event', {data: 'I\'m connected!'});
        });
    </script>
  3. Upgrade from Flask-SocketIO 4.x to 5.x

    main
    Upgrading to Flask-SocketIO 5.x introduces backwards incompatible changes to the Socket.IO protocol. To ensure compatibility, you must also upgrade your JavaScript client to a 3.x release. If your client cannot be upgraded to the latest Socket.IO protocol, you must continue using a Flask-SocketIO 4.x release.
  4. Deploy using Gunicorn

    main

    You can use gunicorn as a web server by specifying an appropriate worker class. Note that due to Gunicorn's limited load balancing, you must use a single worker (-w 1) for Socket.IO. To scale, run multiple single-worker instances behind a load balancer like Nginx.

    Options:

    • Eventlet: Requires eventlet installed.
    • Gevent: Requires gevent installed. If using gevent-websocket, use the GeventWebSocketWorker.
    • Threaded: Best for CPU-heavy applications. Requires the simple-websocket package.
  5. Deploy using uWSGI

    main

    When using uWSGI with gevent, the server can utilize uWSGI's native WebSocket support. The uWSGI binary must be compiled with WebSocket and SSL support.

    Example command to start a server for app.py on port 5000:

    uwsgi --http :5000 --gevent 1000 --http-websockets --master --wsgi-file app.py --callable app
  6. Scale Flask-SocketIO with Multiple Workers

    main

    To scale to large numbers of concurrent clients, deploy multiple workers behind a load balancer. This requires two components:

    1. Sticky Sessions: The load balancer must forward all requests from a single client to the same worker (e.g., using Nginx ip_hash).
    2. Message Queue: A coordinator like Redis, RabbitMQ, or Kafka is required to synchronize broadcasts and rooms across workers.

    Dependencies:

    • Redis: pip install redis
    • RabbitMQ: pip install kombu
    • Kafka: pip install kafka-python

    Monkey Patching: If using eventlet or gevent, you must monkey patch the Python standard library at the very top of your main script to ensure message queue clients work correctly with coroutines.

    # For eventlet
    import eventlet
    eventlet.monkey_patch()
    
    # For gevent
    from gevent import monkey
    monkey.patch_all()
  7. Authenticate SocketIO connections

    main

    Since SocketIO does not use standard HTTP request/response cycles, traditional web forms cannot be used for authentication during the connection. You have two primary options:

    1. Pre-connection Authentication: Perform traditional authentication via HTTP routes first. Store the user's identity in the session or a cookie. When the SocketIO connection is established, the handler will have access to this identity.
    2. Socket.IO Protocol Authentication: Use the Socket.IO protocol's ability to pass an authentication dictionary during the connection. This dictionary is passed as an argument to the connect event handler.

    Using Flask-Login with Flask-SocketIO

    If you use Flask-Login, the current_user context variable is available in SocketIO handlers after login_user() has been called in an HTTP context.

    Note: The @login_required decorator cannot be used on SocketIO handlers. You must implement a custom decorator to handle authentication checks.

    @socketio.on('connect')
    def connect_handler():
        if current_user.is_authenticated:
            emit('my response',
                 {'message': '{0} has joined'.format(current_user.name)},
                 broadcast=True)
        else:
            return False  # not allowed here
  8. Deploy using an Embedded Server

    main

    The simplest deployment strategy is to use socketio.run(app). This method automatically selects the best available web server from the following installed packages: eventlet, gevent, or the Flask development server.

    Note: If neither eventlet nor gevent are installed, it falls back to the Flask development server, which is not intended for production use.

    socketio.run(app)
  9. Initialize Flask-SocketIO in a Flask application

    main

    You can initialize Flask-SocketIO using two patterns: direct attachment to the app object or the init_app() style for factory patterns.

    Important: Always use socketio.run(app) to start your server instead of app.run(). This ensures the correct web server (eventlet, gevent, or Werkzeug) is used to support WebSockets. Using flask run is not recommended as it lacks WebSocket support.

    from flask import Flask
    from flask_socketio import SocketIO
    
    # Pattern 1: Direct initialization
    app = Flask(__name__)
    app.config['SECRET_KEY'] = 'secret!'
    socketio = SocketIO(app)
    
    if __name__ == '__main__':
        socketio.run(app)
    
    # Pattern 2: init_app() style (Application Factory)
    socketio = SocketIO()
    
    def create_app():
        app = Flask(__name__)
        app.config['SECRET_KEY'] = 'secret!'
        socketio.init_app(app)
        return app
    
    if __name__ == '__main__':
        app = create_app()
        socketio.run(app)
  10. Access Flask context globals in SocketIO handlers

    main

    Flask-SocketIO makes SocketIO event handlers behave similarly to regular Flask HTTP routes by pushing application and request contexts.

    Available Globals

    • current_app and g: Available via the application context.
    • request: Available via the request context. It is enhanced with the following members:
      • request.sid: A unique session ID for the connection (used as the initial room).
      • request.namespace: The currently handled namespace.
      • request.event: A dictionary containing message and args for the current event.
    • session: A copy of the user session at the time of connection is made available.

    Important Limitations

    • Session Forking: Modifications to session within a SocketIO handler are preserved for future SocketIO handlers but are not visible to regular HTTP route handlers (because no HTTP cookie can be sent back during a WebSocket connection). If using server-side sessions (e.g., Flask-Session), changes made in HTTP routes can be seen by SocketIO handlers, provided the SocketIO handler does not modify the session itself.
    • Hooks: before_request and after_request hooks are not invoked for SocketIO event handlers.
    • Decorators: Most Flask decorators that rely on a Response object will not work with SocketIO handlers.
  11. Configure asynchronous service providers

    main

    Flask-SocketIO automatically detects which asynchronous framework to use based on what is installed in your environment. The preference order is:

    1. eventlet (Note: gevent is generally preferred over eventlet as eventlet is no longer actively maintained).
    2. gevent
    3. threading (Python standard library)

    Service Options

    • threading: The easiest and most compatible solution. Supports long-polling and WebSocket transports. Works with the Flask development server and Gunicorn in multi-threaded mode.
    • gevent: Supports long-polling and WebSocket transports. Compatible with the Flask development server, gevent's own web server, Gunicorn (with gevent worker), and uWSGI (in gevent mode).
    • eventlet: Supports long-polling and WebSocket transports. Compatible with the Flask development server, eventlet's own web server, and Gunicorn (with eventlet worker).