WebSocket je komunikačný protokol, ktorý umožňuje obojsmernú (full-duplex) komunikáciu medzi klientom a serverom v reálnom čase.
Na rozdiel od klasického HTTP spojenia, ktoré funguje na princípe request → response, WebSocket udržiava trvalé spojenie, cez ktoré môžu klient aj server posielať dáta kedykoľvek.
WebSockety sa často používajú v aplikáciách ako:
chat aplikácie
live notifikácie
online hry
real-time dashboardy
finančné aplikácie s aktuálnymi dátami
Vo Flask aplikáciách sa WebSockety najčastejšie implementujú pomocou knižnice Flask-SocketIO.
WebSockety vo Flasku
Ak si sa niekedy stretol s pojmom WebSocket a chcel by si vedieť, ako funguje v Python aplikácii, tento článok ti ukáže základný princíp.
V klasických webových aplikáciách komunikuje prehliadač so serverom pomocou HTTP protokolu. Tento model funguje jednoducho:
klient pošle request
server vráti response
spojenie sa ukončí
Tento spôsob komunikácie však nie je ideálny pre moderné aplikácie, ktoré potrebujú real-time komunikáciu.
Preto vznikol WebSocket protokol.
Ako fungujú WebSockety
HTTP by mal byť viac-menej bezstavový a klient a server medzi sebou komunikujú iba keď treba, inak je spojenie medzi nimi uzavreté. Navyše, prehliadač (klient) musí požiadať server o komunikáciu a server môže na túto žiadosť odpovedať. Tá žiadosť, to je ten http request. Inak server nevie kontaktovať klienta len tak sám od seba.
Pri websocketoch je to inak. Ide o komunikačný kanál, ktorý sa otvorí raz, na začiatku a potom sa používa na komunikáciu klienta a servera v oboch stranách. To znamená, že server môže posielať dáta zároveň čo klient posiela dáta na server. Toto sa odborne volá full-duplex.
Web socket má menší overheat prenosu dát, vie byť real-time a hlavne, server môže posielať dáta na klienta bez toho, aby si ich klient musel explicitne vyžiadať requestom. Toto je užitočné napríklad pri aplikáciách, ktoré zobrazujú real time dáta a server posiela tieto dáta klientovi. Takže ak nastane nejaká zmena dát, server ich proste pošle na klienta.
Toto predtým nebolo možné spraviť iba pomocou http protokolu.
Minimálny príklad
Najlepšie je vyskúšať si tieto koncepty v praxi. Dnes budeme pracovať s Flaskom, knižnicou SocketIO a javascript knižnicami socket.io a jQuery. Budem predpokladať, že Flask aplikácie aspoň trochu poznáš.
Začneme tým, že si vytvoríme nové virtuálne prostredie:
Nainštalujeme závislosti, ktoré budeme potrebovať:
(venv)$ pip install flask, flask-socketio
V čase písania tohto článku som používal verzie Flask==1.0.2 a Flask-SocketIO=3.0.1.
Keď už máme pripravené prostredie a nainštalované závislosti, spravíme nový súbor server.py
from flask import Flask
from flask import render_template
from flask_socketio import SocketIO
app = Flask(__name__)
app.config["SECRET_KEY"] = "secret"
socketio = SocketIO(app)
@app.route("/")
def index():
return render_template("index.jinja")
@socketio.on("event")
def handle_event(data):
print(data)
if __name__ == '__main__':
socketio.run(app, debug=True)
Na začiatku máme importy ako pre každú inú Flask aplikáciu, avšak pribudlo nám tam from flask_socketio import SocketIO. Tento naimportovaný modul je v podstate to isté ako iné Flask rozšírenia.
Inicializáciu websocketov vo Flask aplikácií spravíme pomocou riadku socketio = SocketIO(app). Pomocou tohto objektu socketio budeme príjmať a odosielať správy.
Minimálna aplikácia by mala mať aspoň jednu stránku. V našom prípade to bude index.jinja. Toto je treba pretože musíme poskytnúť aj klientskú časť našej aplikácie. Tam bude javascript knižnica socketio a nejaké ďalšie funkcie.
Websockety vedia prijímať a posielať správy. Spravíme zatiaľ len prijímanie správ. Pomocou riadku socketio.on("event")definujem handler pre udalosť event. V tomto prípade jednoducho vypíšem dáta na konzolu.
Posielanie a prijímanie dát na oboch stranách (klient a server) prebieha ako event. Toto je dôležitý fakt, pretože architektúra aplikácie založenej na eventoch (event driven architecture) funguje trošku inak ako klasické volanie funkcie. Nehovorím, aby si mal z toho paniku teraz, ale maj to na pamäti.
Ak poznáš Flask aplikácie, tak spustenie appky vyzerá zväčša takto
if __name__ == "__main__":
app.run("0.0.0.0", debug=True)
My ale musíme appku spustiť inak, pretože používame websockety. Spustíme ju pomocou objektu socketio, ktorý sme si vytvorili na začiatku.
if __name__ == '__main__':
socketio.run(app, debug=True)
Teraz musíme ešte vytvoriť 2 súbory. Snažíme sa renderovať index.jinja a taktiež musíme vytvoriť hlavný javascript súbor, do ktorého budeme písať klientskú časť našej websocketovej ukážky.
Vytvorím priečinok templates a do neho súbor index.jinja
Dôležité sú 3 importy v hlavičke html dokumentu. Prvý importuje jQuery, druhý importuje knižnicu na prácu so socketmi socketio a posledný import je pre náš main.js súbor, ktorý musíme ešte vytvoriť.
Inak, tento html dokument obsahuje len jeden formulár s jedným tlačítkom. To budeme používať na posielanie správy cez websocket.
Vytvoríme priečinok static v ňom js a v ňom už konečne súbor main.js
Toto je hlavná logika klientskej časti. Z tadeto budeme prijímať a posielať správy cez websockety tak isto ako na serverovej časti.
Pomocou riadku var socket = io.connect(url); sa pripojím na môj server. Následne pomocou jQuery upravím správanie buttonu, aby pri stlačení poslal správu. Na to slúži funkcia socket.emit()
Okej, základ máme hotový a môžeme teraz skúšať posielať správy. Aplikáciu spustím pomocou príkazu:
(venv)$ python server.py
WebSocket transport not available. Install eventlet or gevent and gevent-websocket for improved performance.
* Serving Flask app "server" (lazy loading)
* Environment: production
WARNING: Do not use the development server in a production environment.
Use a production WSGI server instead.
* Debug mode: on
* Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
* Restarting with stat
WebSocket transport not available. Install eventlet or gevent and gevent-websocket for improved performance.
* Debugger is active!
* Debugger PIN: 478-618-530
Otvorím prehliadač na http://localhost:5000 a zobrazí sa mi jeden button. Keď ho stlačím na konzole mi vyskočí:
test message
Poďme teda preskúmať, aké možnosti nám poskytuje táto knižnica socketio.
Príjmanie správ
Ako som už spomínal, prijímanie správ na oboch stranách prebieha ako event. V Pythone musíme pre takýto event definovať handler. V javascripte používame tzv. callbacky. V princípe ide o to isté, ale každý jazyk má svoje vlastné technické riešenie a my si toho musíme byť vedomí.
Každý event, ktorý chcem prijať musím mať nejaké meno. V príklade sme mali názov event. Môžem ale použiť čokoľvek
Taktiež dáta sa automaticky menia na príslušný typ. Ak v javascripte pošlem string, tak string dostanem aj na serveri. Tak isto to platí pre iné dátové typy
Namespace patrí medzi ďalšie funkcie, ktoré mám knižnica SocketIO ponúka. Každý event si môžeme rozdeliť podľa namespaceov. To nám dáva ďalšie možnosti organizácie eventov.
Ďalšia vychytávka je to, že každý event, ktorý pošleme, vie zavolať callback potom, čo sa vykonal. Napríklad z javascriptu pošlem nejaké dáta na server a server mi ešte dodatočne potvrdí, že dáta boli spracované. Aha takto
Musím si otvoriť v prehliadači konzolu (ja používam chrome) a keď stlačím tlačítko, dostanem výpis na konzolu
Posielanie správ
Posielať eventy sme už posielali, ale iba z javascriptu. V Pythone to vyzerá veľmi podobne. Používame 2 funkcie send a emit medzi ktorými je zásadný rozdiel.
Najprv musíme importovať z knižnice flask-socketio
from flask_socketio import send
from flask_socketio import emit
Všimni si, že teraz som použil handler, ktorý spracováva event s názvom message. Nie je to náhoda. Ide totiž o to, že funkcia send posiela tzv. unnamed event. Tieto eventy sa vždy posielajú na handler, ktorý spracúva message.
Narozdiel od funkcie send, funkcia emit posiela už konkrétny event a musíš mu dať názov. Skúsme teda pozmeniť náš príklad
Veľmi užitočná funkcia je broadcastovanie, čo už z názvu vyplýva, že eventy sa budú vysielať na všetkých pripojených klientov. Dajme tomu, že zmeníme funciu emit na broadcastovanie
Teraz, keď si otvoríš 2 prehliadače a v jednom stlačíš button, výsledok súčtu sa ukáže vo všetkých prehliadačoch
note: callbacky sa pri broadcastovaní nebudú vykonávať
Záver
WebSockety umožňujú real-time komunikáciu medzi klientom a serverom. Vo Flask aplikáciách ich môžeme jednoducho implementovať pomocou knižnice Flask-SocketIO. Pomocou WebSocketov môžeme vytvárať moderné aplikácie, ktoré:
aktualizujú dáta v reálnom čase
komunikujú bez neustálych HTTP requestov
efektívnejšie pracujú s dátami
V ďalšom článku si ukážeme praktickú aplikáciu postavenú na WebSocketoch.
Najčastejšie otázky FAQ: WebSockety vo Flasku
Čo je WebSocket?
WebSocket je protokol umožňujúci obojsmernú komunikáciu medzi klientom a serverom v reálnom čase.
Na čo sa používajú WebSockety?
Používajú sa napríklad pri chat aplikáciách, live notifikáciách, online hrách alebo real-time dashboardoch.
Ako implementovať WebSockety vo Flasku?
Najčastejšie sa používa knižnica Flask-SocketIO, ktorá umožňuje jednoduché vytvorenie WebSocket servera.
Je WebSocket rýchlejší než HTTP?
WebSocket má menší overhead a umožňuje trvalé spojenie medzi klientom a serverom, čo je efektívnejšie pri real-time komunikácii.
Ahoj, volám sa Miro a som Pythonista. Programovať som začal na strednej. Vtedy frčal ešte turbo pascal. Potom prišiel matfyz, kadejaké zveriny ako Haskell, no najviac sa mi zapáčil Python.
Od vtedy v Pythone robím všetko. Okrem vlastných vecí čo si programujem pre radosť, som pracoval v ESETe ako automatizér testovania. Samozrejme, všetko v Pythone. Potom som skočil do inej firmy, tam taktiež Python na automatické testovanie aj DevOps. Viacej krát som účinkoval ako speaker na PyCon.sk, kde som odovzdával svoje skúsenosti.
Medzi moje obľúbené oblasti teda parí DevOps, Automatizovanie testovania a web development (hlavne backend).