FLASK-SOCKETIO(1) Flask-SocketIO FLASK-SOCKETIO(1) (NAME) flask-socketio - flask-socketio Flask-SocketIO Flask . SocketIO Javascript Python C++ Java Swift . (INTRODUCTION) (Installation) pip : pip install flask-socketio (Requirements) Flask-SocketIO Python 3.8+ . (asynchronous) : o threading Python long-polling WebSocket . Flask Gunicorn (multi-threaded) . o gevent long-polling WebSocket . gevent Flask gevent Gunicorn ( gevent) uWSGI ( gevent) . o eventlet long-polling WebSocket gevent . eventlet Flask eventlet Gunicorn ( eventlet) . . eventlet gevent . eventlet gevent threading . (message queue) (broadcasting) . Redis RabbitMQ Kafka Kombu . Socket.IO Javascript . Swift Java C++ . Socket.IO . python-socketio ( Socket.IO Flask-SocketIO ) ..SS " (Version compatibility)" Socket.IO . JavaScript Socket.IO Engine.IO . +-------------+-----------------------+-----------------------+--------------------------+--------------------------+--------------------------+ | | | | | | | |Socket.IO | | | Flask-SocketIO | python-socketio | python-engineio | | | Socket.IO | Engine.IO | | | | |JavaScript | | | | | | +-------------+-----------------------+-----------------------+--------------------------+--------------------------+--------------------------+ |0.9.x | 1, 2 | 1, 2 | | | | | | | | | | | +-------------+-----------------------+-----------------------+--------------------------+--------------------------+--------------------------+ |1.x 2.x | 3, 4 | 3 | 4.x | 4.x | 3.x | +-------------+-----------------------+-----------------------+--------------------------+--------------------------+--------------------------+ |3.x 4.x | 5 | 4 | 5.x | 5.x | 4.x | +-------------+-----------------------+-----------------------+--------------------------+--------------------------+--------------------------+ (GETTING STARTED) (Initialization) Flask-SocketIO Flask : from flask import Flask, render_template from flask_socketio import SocketIO app = Flask(__name__) app.config['SECRET_KEY'] = 'secret!' socketio = SocketIO(app) if __name__ == '__main__': socketio.run(app) init_app() : from flask import Flask, render_template from flask_socketio import SocketIO 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) . . socketio.run() Flask app.run() . (debug) Werkzeug socketio.run() . (production) eventlet gevent . eventlet gevent Werkzeug . flask run Flask 0.11 Flask-SocketIO Werkzeug Flask-SocketIO WebSocket . flask run WebSocket eventlet gevent socketio.run(app) . Socket.IO : SocketIO . JavaScript . Flask-SocketIO (handlers) view . : @socketio.on('message') def handle_message(data): print('received message: ' + data) . JSON : @socketio.on('json') def handle_json(json): print('received json: ' + str(json)) . string bytes int JSON : @socketio.on('my event') def handle_my_custom_event(json): print('received json: ' + str(json)) : @socketio.on('my_event') def handle_my_custom_event(arg1, arg2, arg3): print('received args: ' + arg1 + arg2 + arg3) Python @socketio.event (decorated function) : @socketio.event def my_custom_event(arg1, arg2, arg3): print('received args: ' + arg1 + arg2 + arg3) . message json connect disconnect . Flask-SocketIO namespace SocketIO (multiplex) : @socketio.on('my event', namespace='/test') def handle_my_custom_namespace_event(json): print('received json: ' + str(json)) namespace namespace '/' . on_event : def my_function_handler(data): pass socketio.on_event('my event', my_function_handler, namespace='/test') (acknowledgement callback) . : @socketio.on('my event') def handle_my_custom_event(json): print('received json: ' + str(json)) return 'one', 2 'one' 2 . ..SS " (Sending Messages)" SocketIO send() emit() . : from flask_socketio import send, emit @socketio.on('message') def handle_message(message): send(message) @socketio.on('json') def handle_json(json): send(json, json=True) @socketio.on('my event') def handle_my_custom_event(json): emit('my response', json) send() emit() . (namespaces) send() emit() . namespace : @socketio.on('message') def handle_message(message): send(message, namespace='/chat') @socketio.on('my event') def handle_my_custom_event(json): emit('my response', json, namespace='/chat') (tuple) : @socketio.on('my event') def handle_my_custom_event(json): emit('my response', ('foo', 'bar', json), namespace='/chat') SocketIO (acknowledgment callbacks) : def ack(): print('message was received!') @socketio.on('my event') def handle_my_custom_event(json): emit('my response', json, callback=ack) Javascript . (server-side) . ..SS " (Broadcasting)" SocketIO . Flask-SocketIO broadcast=True send() emit() : @socketio.on('my event') def handle_my_custom_event(data): emit('my response', data, broadcast=True) namespace . namespace namespace (global) . (callbacks) . . . ( ) . socketio.send() socketio.emit() : def some_function(): socketio.emit('some event', {'data': 42}) socketio.send() socketio.emit() (context-aware) send() emit() . broadcast=True . (Rooms) . . Flask-SocketIO join_room() leave_room() : from flask_socketio import join_room, leave_room @socketio.on('join') def on_join(data): username = data['username'] room = data['room'] join_room(room) send(username + ' has entered the room.', to=room) @socketio.on('leave') def on_leave(data): username = data['username'] room = data['room'] leave_room(room) send(username + ' has left the room.', to=room) send() emit() to . (session ID) request.sid . . . socketio.send() socketio.emit() to . (session ID) to ..SS (Connection Events) Flask-SocketIO . (handlers) : @socketio.on('connect') def test_connect(auth): emit('my response', {'data': 'Connected'}) @socketio.on('disconnect') def test_disconnect(reason): print('Client disconnected, reason:', reason) auth . . None . . False ConnectionRefusedError . . . : from flask_socketio import ConnectionRefusedError @socketio.on('connect') def connect(): if not self.authenticate(request.args): raise ConnectionRefusedError('unauthorized!') reason . flask_socketio.SocketIO.reason <#flask_socketio.SocketIO.reason> . (namespace) . (Class-Based Namespaces) . flask_socketio.Namespace <# flask_socketio.Namespace> : from flask_socketio import Namespace, emit class MyCustomNamespace(Namespace): def on_connect(self): pass def on_disconnect(self, reason): pass def on_my_event(self, data): emit('my_response', data) socketio.on_namespace(MyCustomNamespace('/test')) on_ . my_event on_my_event . . . flask_socketio.SocketIO <# flask_socketio.SocketIO> namespace . ..SS " (Error Handling)" Flask-SocketIO (exceptions) : @socketio.on_error() # Handles the default namespace def error_handler(e): pass @socketio.on_error('/chat') # handles the '/chat' namespace def error_handler_chat(e): pass @socketio.on_error_default # handles all namespaces without an explicit error handler def default_error_handler(e): pass . request.event : from flask import request @socketio.on("my error event") def on_my_event(data): raise RuntimeError() @socketio.on_error_default def default_error_handler(e): print(request.event["message"]) # "my error event" print(request.event["args"]) # (data,) (Debugging and Troubleshooting) : socketio = SocketIO(logger=True, engineio_logger=True) logger Socket.IO engineio_logger Engine.IO . stderr True logging Python . False . 400 . (IMPLEMENTATION NOTES) Flask (Access to Flask's Context Globals) SocketIO (routes) SocketIO . SocketIO (context) . Flask-SocketIO HTTP SocketIO . : o (application context) (push) current_app g . o (request context) request session . WebSocket . o request sid (session ID) . (room) . o request namespace event . event message args . o session . SocketIO . SocketIO SocketIO HTTP . SocketIO ("fork") . HTTP SocketIO . Flask-Session Flask-KVSession HTTP SocketIO SocketIO . o before_request after_request SocketIO . o SocketIO SocketIO Response Flask SocketIO . . HTTP SocketIO HTTP . SocketIO . SocketIO . (user session) SocketIO SocketIO . Socket.IO . . connect . Flask-Login Flask-SocketIO Flask-SocketIO Flask-Login . Flask-Login login_user() SocketIO current_user : @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 login_required SocketIO : import functools from flask import request from flask_login import current_user from flask_socketio import disconnect, emit def authenticated_only(f): @functools.wraps(f) def wrapped(*args, **kwargs): if not current_user.is_authenticated: disconnect() else: return f(*args, **kwargs) return wrapped @socketio.on('my event') @authenticated_only def handle_my_custom_event(data): emit('my response', {'message': '{0} has joined'.format(current_user.name)}, broadcast=True) (DEPLOYMENT) Flask-SocketIO . . (Embedded Server) socketio.run(app) . . eventlet gevent Flask. eventlet gevent socketio.run(app) . Flask . gevent uWSGI . uWSGI ..SS " Gunicorn (Gunicorn Web Server)" socketio.run(app) gunicorn eventlet gevent . gunicorn eventlet gevent . eventlet gunicorn : gunicorn --worker-class eventlet -w 1 module:app gevent : gunicorn -k gevent -w 1 module:app gunicorn gevent WebSocket gevent-websocket gevent WebSocket . : gunicorn -k geventwebsocket.gunicorn.workers.GeventWebSocketWorker -w 1 module:app Gunicorn (threaded worker) simple-websocket WebSocket . CPU eventlet gevent (green threads) . : gunicorn -w 1 --threads 100 module:app module (application instance) app . (load balancing) gunicorn . -w 1 . gunicorn (single-worker) nginx . uWSGI (uWSGI Web Server) uWSGI gevent Socket.IO uWSGI WebSocket . uWSGI . uWSGI . WebSocket (WebSocket transport) WebSocket SSL . uWSGI app.py 5000 : $ uwsgi --http :5000 --gevent 1000 --http-websockets --master --wsgi-file app.py --callable app nginx (reverse proxy) . 1.4 nginx WebSocket . nginx HTTP WebSocket : server { listen 80; server_name _; location / { include proxy_params; proxy_pass http://127.0.0.1:5000; } location /static/ { alias /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://127.0.0.1:5000/socket.io; } } (load balancing) Socket.IO : upstream socketio_nodes { ip_hash; server 127.0.0.1:5000; server 127.0.0.1:5001; server 127.0.0.1:5002; # to scale the app, just add more nodes here! } server { listen 80; server_name _; location / { include proxy_params; proxy_pass http://127.0.0.1:5000; } location /static/ { alias /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; } } nginx (production) SSL ..SS Worker Flask-SocketIO 2.0 worker (load balancer) . worker Flask-SocketIO . worker Flask-SocketIO : o HTTP worker . " (sticky sessions)" . nginx ip_hash . Gunicorn worker sticky sessions . o (message queue) Redis RabbitMQ (broadcasting) (rooms) . : o Redis redis (pip install redis). o RabbitMQ kombu (pip install kombu). o Kafka kafka-python (pip install kafka-python). o Kombu Kombu . o eventlet gevent (monkey patching) (coroutine) . eventlet monkey patching : import eventlet eventlet.monkey_patch() gevent monkey patch : from gevent import monkey monkey.patch_all() monkey patching import . Flask-SocketIO . Socket.IO message_queue SocketIO : socketio = SocketIO(app, message_queue='redis://') message_queue URL . redis URL 'redis://' . RabbitMQ URL 'amqp://' . Kafka URL kafka:// . Kombu URL ..SS (Emitting from an External Process) SocketIO worker Celery . SocketIO SocketIO . eventlet Redis Python (broadcast) : socketio = SocketIO(message_queue='redis://') socketio.emit('my event', {'data': 'foo'}, namespace='/test') SocketIO Flask (constructor) . channel SocketIO . SocketIO . eventlet gevent Flask-SocketIO monkey patching . Python monkey patching Python (hang) . SocketIO eventlet gevent . coroutine . worker Celery eventlet gevent . coroutine monkey patching coroutine . (Cross-Origin Controls) (same-origin policy) . : o HTTP WebSocket Origin (scheme) (host) URL . 400 . o Origin . cors_allowed_origins . . '*' (CSRF) . FLASK-SOCKETIO 5.X 4.X (UPGRADING TO FLASK-SOCKETIO 5.X FROM THE 4.X RELEASES) Socket.IO (backwards incompatible) . 5.x Flask-SocketIO . JavaScript 3.x Socket.IO Flask-SocketIO 4.x . : o '/' . o sid sid Engine.IO . o Flask-SocketIO (timeout) JavaScript 25 5 . o ping/pong . ping pong . o (payload) long--polling 100MB 1MB . o io . class flask_socketio.SocketIO(app=None, **kwargs) Flask-SocketIO. o app -- flask. socketio.init_app(app) . o manage_session -- True Socket.IO . False Flask . Flask True . False HTTP Socket.IO . o message_queue -- URL . . o channel -- . . SocketIO . o path -- Socket.IO . 'socket.io' . . o resource -- path. o kwargs -- Socket.IO Engine.IO. Socket.IO : o client_manager -- . . o logger -- True . False . False . logger False . o serializer -- . 'default' 'pickle' 'msgpack' 'cbor'. Packet encode() decode() . . o json -- JSON . json dumps loads . JSON . o async_handlers -- True . False . True . o always_connect -- False connect False . True connect False . connect True . False . o namespaces -- . ['/'] . '*' . Engine.IO : o async_mode -- . (Deployment) . "threading" "eventlet" "gevent" "gevent_uwsgi". "eventlet" "gevent_uwsgi" "gevent" "threading" . . o ping_interval -- . . . o ping_timeout -- . . o max_http_buffer_size -- . ,, . HTTP long-polling WebSocket . o allow_upgrades -- . True . o http_compression -- polling . True . o compression_threshold -- . . o cookie -- HTTP . 'name' . None () . o cors_allowed_origins -- . . '*' ['*'] [] CORS. o cors_credentials -- ( ) . True . o monitor_clients -- True . ( ) False . True . o transports -- . 'polling' 'websocket'. ['polling', 'websocket'] . o engineio_logger -- Engine.IO True . False . False . engineio_logger False . class reason . CLIENT_DISCONNECT = 'client disconnect' . PING_TIMEOUT = 'ping timeout' (Ping timeout). SERVER_DISCONNECT = 'server disconnect' . TRANSPORT_CLOSE = 'transport close' (Transport close). TRANSPORT_ERROR = 'transport error' (Transport error). on(message, namespace=None) SocketIO. SocketIO . : @socketio.on('my event', namespace='/chat') def handle_my_custom_event(json): print('received json: ' + str(json)) o message -- . . 'message' (payload) 'json' JSON 'connect' 'disconnect' . o namespace -- . . on_error(namespace=None) SocketIO. . SocketIO (exception) . . : @socketio.on_error(namespace='/chat') def chat_error_handler(e): print('An error has occurred: ' + str(e)) namespace -- . . on_error_default(exception_handler) SocketIO. . : @socketio.on_error_default def error_handler(e): print('An error has occurred: ' + str(e)) on_event(message, handler, namespace=None) SocketIO. on_event 'on' . : def on_foo_event(json): print('received json: ' + str(json)) socketio.on_event('my event', on_foo_event, namespace='/chat') o message -- . . 'message' 'json' JSON 'connect' 'disconnect' . o handler -- () . o namespace -- . . event(*args, **kwargs) . on() . : @socketio.event def my_event(data): print('Received data: ', data) : @socketio.on('my_event') def my_event(data): print('Received data: ', data) : @socketio.event(namespace='/test') def my_event(data): print('Received data: ', data) emit(event, *args, **kwargs) SocketIO . SocketIO (emit) . JSON (payload) . (context) SocketIO ( ) HTTP (background task) . : @app.route('/ping') def ping(): socketio.emit('ping event', {'data': 42}, namespace='/chat') o event -- . o args -- JSON (payload). o namespace -- (namespace) . (global) . o to -- (room) (session ID) . . o include_self -- True (broadcasting) False . o skip_sid -- (session id) . . sid . o callback -- . . (callback) . call(event, *args, **kwargs) SocketIO . (emit) (callback) . (timeout) TimeoutError . Socket.IO . : def get_status(client, data): status = call('status', {'data': data}, to=client) o event -- . o args -- JSON (payload). o namespace -- . . o to -- (session ID) . o timeout -- . TimeoutError . 60 . o ignore_queue -- (message queue) . True . . False . send(data, json=False, namespace=None, to=None, callback=None, include_self=True, skip_sid=None, **kwargs) SocketIO . SocketIO . JSON . emit() . SocketIO . o data -- JSON. o json -- True message JSON False. o namespace -- . . o to -- . . o include_self -- True False . o skip_sid -- . . sid . o callback -- . . . close_room(room, namespace=None) . . SocketIO . o room -- . o namespace -- . . run(app, host=None, port=None, **kwargs) SocketIO. o app -- (instance) Flask. o host -- (hostname) IP . 127.0.0.1 ..IP o 2 port -- () . 5000 . o debug -- True False . o use_reloader -- True Flask False . o reloader_options -- Flask extra_files reloader_type . o extra_files -- Flask . None . reloader_options . o log_output -- True . False . True False . threading . o allow_unsafe_werkzeug -- True Werkzeug . False . True . o kwargs -- . . gunicorn . stop() SocketIO. HTTP SocketIO . start_background_task(target, *args, **kwargs) . . (Parameters) o target -- . o args -- . o kwargs -- . join() . sleep(seconds=0) () . . test_client(app, namespace=None, query_string=None, headers=None, auth=None, flask_test_client=None) Socket.IO Flask-SocketIO . Flask Test Client Socket.IO . (Parameters) o app -- Flask. o namespace -- . (global) . o query_string -- (query string). o headers -- HTTP. o auth -- . o flask_test_client -- Flask . Flask Flask HTTP Socket.IO . flask_socketio.emit(event, *args, **kwargs) (emit) SocketIO. SocketIO . (blob) JSON (payload) . SocketIO (context) . : @socketio.on('my event') def handle_my_custom_event(json): emit('my response', {'data': 42}) (Parameters) o event -- . o args -- JSON (payload). o namespace -- . . '/' . o callback -- (callback) (acknowledgement) . o broadcast -- True False . o to -- (session ID) . broadcast False . o include_self -- True (broadcasting) False . o skip_sid -- (session id) . . sid . o ignore_queue -- (message queue) . True . . False . flask_socketio.send(message, **kwargs) SocketIO..sp SocketIO . (blob) JSON . emit() . SocketIO . o message -- JSON. o json -- True message JSON False. o namespace -- . . (global) . o callback -- (callback) (acknowledgement) . o broadcast -- True False . o to -- (session ID) . broadcast False . o include_self -- True (broadcast) False . o skip_sid -- . . sid (list) . o ignore_queue -- (message queue) . True . . False . flask_socketio.join_room(room, sid=None, namespace=None) . . (event context) . SocketIO . : @socketio.on('join') def on_join(data): username = session['username'] room = data['room'] join_room(room) send(username + ' has entered the room.', to=room) o room -- . o sid -- . (request context) . o namespace -- . . flask_socketio.leave_room(room, sid=None, namespace=None) . . . : @socketio.on('leave') def on_leave(data): username = session['username'] room = data['room'] leave_room(room) send(username + ' has left the room.', to=room) o room -- . o sid -- . . o namespace -- . . flask_socketio.close_room(room, namespace=None) . . o room -- . o namespace -- . . flask_socketio.rooms(sid=None, namespace=None) . Socket.IO . o sid -- . . o namespace -- . . flask_socketio.disconnect(sid=None, namespace=None, silent=False) . . disconnect . : @socketio.on('message') def receive_message(msg): if is_banned(session['username']): disconnect() else: # ... o sid -- . (request context) . o namespace -- . . o silent -- . class flask_socketio.Namespace(namespace=None) trigger_event(event, *args) (handler) . (overload) . (dispatching) (override) . emit(event, data=None, room=None, include_self=True, namespace=None, callback=None) . send(data, room=None, include_self=True, namespace=None, callback=None) . close_room(room, namespace=None) . class flask_socketio.SocketIOTestClient(app, socketio, namespace=None, query_string=None, headers=None, auth=None, flask_test_client=None) Flask-SocketIO . Flask Socket.IO . o app -- Flask. o socketio -- SocketIO . o namespace -- . (global) . o query_string -- (query string). o headers -- (headers) HTTP. o auth -- . o flask_test_client -- Flask . Flask Flask HTTP Socket.IO . is_connected(namespace=None) . namespace -- . . connect(namespace=None, query_string=None, headers=None, auth=None) . o namespace -- . . o query_string -- (query string). o headers -- HTTP. o auth -- . . . disconnect(namespace=None) . namespace -- . . emit(event, *args, **kwargs) . o event -- . o *args -- . o callback -- True (callback) False. . . o namespace -- . . send(data, json=False, callback=False, namespace=None) JSON . o data -- . o json -- True JSON False . o callback -- True (callback) False. . . o namespace -- . . get_received(namespace=None) ..sp . . namespace -- . (global) . o <> o <> o <> (AUTHORS) Miguel Grinberg (COPYRIGHT) 2018, Miguel Grinberg March 14, 2026 FLASK-SOCKETIO(1)