In questa lezione vedremo come implementare un WebSocket server utilizzando un linguaggio di scripting che sta diffondendosi sempre di più anche per l'implementazione di server web, sopratutto nei progetti più recenti ed innovativi: Python. Per i nostri scopi, ci affideremo a Tornado, un framework che consente di implementare un vero e proprio web server, ma che in questo ambito utilizzeremo principalmente per la sua capacità di gestire il protocollo che sta alla base delle WebSocket.
Installazione
Nel seguito faremo riferimento a Python 2.7, così da poter coprire le necessità degli sviluppatori che utilizzano la maggior parte delle versioni di questo linguaggio. Supponiamo, inoltre, che l'interprete Python sia già installato sul proprio sistema operativo; se così non fosse, rimandiamo al sito ufficiale per maggiori informazioni sulla procedura di installazione specifica per la vostra piattaforma.
Avendo a disposizione un interprete Python, la prima cosa di cui abbiamo bisogno è installare Tornado. Possiamo farlo tramite l'utility pip
, che è installata di default se utilizziamo una versione di Python superiore alla 2.7.9:
pip install tornado
Se non abbiamo a disposizione pip
, possiamo ottenerlo seguendo questa procedura, oppure possiamo decidere di scaricare Tornado dal sito ufficiale.
Il codice
Completata l'installazione di Tornado, non resta che dare un'occhiata al codice. Avremo bisogno di definire una classe che erediti da WebSocketHandler
, a sua volta definita in tornado.websocket
. La classe che scriveremo (che chiameremo per semplicità MyWebSocketServer
) dovrà implementare tre metodi, in maniera del tutto analoga a quanto visto con C# e Java:
-
open
: questo metodo sarà eseguito al termine dell'handshake iniziale (effettuato comunque in maniera trasparente allo sviluppatore), quando verrà aperta la WebSocket; -
on_message
: tutte le volte che il server riceverà un messaggio da un client, sarà eseguito questo metodo, che come vedremo avrà accesso al corpo del messaggio stesso, potendo rispondere ad esso in funzione del suo contenuto; -
on_close
: al termine della connessione, quando la WebSocket verrà chiusa, sarà eseguito questo metodo.
La classe che definiremo sarà quindi simile alla seguente:
class MyWebSocketServer(tornado.websocket.WebSocketHandler):
def open(self):
# metodo eseguito all'apertura della connessione
def on_message(self, message):
# metodo eseguito alla ricezione di un messaggio
# la stringa 'message' rappresenta il messaggio
# esempio: stampa il messaggio
print 'Messaggio ricevuto: %s' % message
def on_close(self):
# metodo eseguito alla chiusura della connessione
Una volta definita questa classe, per completare il programma abbiamo bisogno di un server HTTP che risponda a tutte le richieste di apertura di una WebSocket. Possiamo implementarlo, specificando anche la porta su cui rimarrà in ascolto, utilizzando le classi fornite da Tornado. Di seguito è mostrato un esempio completo:
import tornado.httpserver
import tornado.websocket
import tornado.ioloop
import tornado.web
import socket
class MyWebSocketServer(tornado.websocket.WebSocketHandler):
def open(self):
# metodo eseguito all'apertura della connessione
print 'Nuova connessione'
def on_message(self, message):
# metodo eseguito alla ricezione di un messaggio
# la stringa 'message' rappresenta il messaggio
print 'Messaggio ricevuto: %s' % message
def on_close(self):
# metodo eseguito alla chiusura della connessione
print 'Connessione chiusa'
def check_origin(self, origin):
return True
application = tornado.web.Application([
(r'/websocketserver', MyWebSocketServer),
])
if __name__ == "__main__":
http_server = tornado.httpserver.HTTPServer(application)
http_server.listen(8000)
tornado.ioloop.IOLoop.instance().start()
L'oggetto http_server
è proprio il nostro web server, inizializzato con l'oggetto application
. Quest'ultimo, a sua volta, è quello che permette al nostro WebSocket server di funzionare come ci aspettiamo, in quanto accetta proprio la classe MyWebSocketServer
come parametro, insieme ad una stringa che identifica il nome dell'applicazione. In altre parole, su JavaScript, potremo creare la nostra WebSocket con la seguente richiesta:
var websocket = new WebSocket("ws://ilmioserver.com:8000/websocketserver");
Alternative a Tornado
Se la nostra intenzione è implementare un WebSocket server senza alcuna dipendenza da librerie esterne, una possibile soluzione è quella proposta da Jamie Kirkpatrick, che ha pubblicato un Gist pensato proprio per tale scopo. Sebbene tale approccio sia inevitabilmente più complesso, può tornare utile in alcuni casi.
Se invece vogliamo optare per qualcosa di più semplice, ma non ci piace o non vogliamo utilizzare Tornado, alcune delle principali alternative sono rappresentate dalle seguenti librerie: