SlideShare ist ein Scribd-Unternehmen logo
1 von 34
Downloaden Sie, um offline zu lesen
SOCKET E SOCKETSERVER
IL FRAMEWORK PER I SERVER INTERNET IN PYTHON

           Marco Spisto, Giovanni Bajo
                 PyCon Italia Quattro
                Firenze, 9 maggio 2010
SOMMARIO

• Servizi di rete con Python
• Modulo di basso livello: socket
•   Modulo di alto livello: SocketServer
      • Struttura del modulo
      • Classi per il server
      • Classi per la gestione della connessione client
      • Gestione concorrente delle richieste

•   Caso d’uso: il server HTTP della libreria standard
SERVIZI DI RETE CON PYTHON

• Basso livello: socket
  Wrapper per il modulo implementato in C
• Alto livello: SocketServer
  Framework costruito sul modulo socket
OGGETTI SOCKET

•   Costruttore
    socket(family, type)
      • family	

 famiglia di indirizzi di rete (e.g.: IPv4)

      • type 	

  	

 tipo di trasporto dati (e.g.: stream, datagrammi)
•   Metodi per la comunicazione
       •   mysocket.recv(n_bytes)
           ricezione (lettura) di al più n_bytes
       •   mysocket.send(data)
           invio della stringa data
ESEMPIO 1
           Client                           Server
  collegamento al server           configurazione e avvio
     invio stringa di dati           attesa connessione
ricezione dei dati dal server    lettura dati inviati dal client
                                conversione dati in maiuscolo
                                 invio dati elaborati al client
ESEMPIO 1: SERVER
import socket

HOST = ""	 	      	     # qualsiasi indirizzo disponibile sulla macchina che ospita il server
PORT = 10001	     	     # porta TCP sulla quale il server si mette in ascolto
SIZE = 1024		     # numero di byte da leggere



def start(indirizzo):                                                   def handle(connection):
	     # creazione del socket                                            	     request, address = connection
	     s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
	     s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)           	     print "Connessione da: %s:%d" % address

	     # configurazione                                                  	     # lettura dei dati inviati dal client
	     s.bind(indirizzo)                                                 	     data = request.recv(SIZE)
	     s.listen(5)                                                       	     print "-->", data

	     # attesa connessione                                              	     # elaborazione dati ricevuti
	     client = s.accept()                                               	     data = data.upper()

	     # gestione connessione                                            	     # invio di dati al client
	     handle(client)                                                    	     request.send(data)
                                                                        	     print "<--", data
	     # chiusura socket
	     s.close()




if __name__ == '__main__':
	     indirizzo = HOST, PORT
	     start(indirizzo)
ESEMPIO 1: CLIENT
import socket

HOST = "127.0.0.1"	     # indirizzo IPv4 della macchina che ospita il server
PORT = 10001	     	     # porta TCP sulla quale il server si mette in ascolto
SIZE = 1024		     # numero di byte da leggere



if __name__ == '__main__':
	     indirizzo = HOST, PORT

	     print "Connessione verso %s:%d" % indirizzo
	     s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
	     s.connect(indirizzo)

	     data = "ciao"
	     print "-->", data
	     s.send(data)

	     data = s.recv(SIZE)
	     print "<--", data
MODULO SOCKETSERVER

         Strutturato con due classi principali

               Server              Handler




        Implementazione          Gestione
            servizio              client

N.B. in Python 3 il modulo si chiamerà socketserver
FUNZIONAMENTO DEL SERVER

•   Classe principale: BaseServer
•   Costruttore:
    BaseServer(address, HandlerFactory)
      • address	

  	

 	

 	

 coppia: indirizzo, porta
      • HandlerFactory	

 	

   classe che viene istanziata
        	

 	

 	

 	

 	

 per gestire una singola connessione con il client
•   Metodi di controllo:
      •   handle_request()	

accettazione  singola connessione
      •   serve_forever()	

 ciclo (infinito) di accettazione connessioni
ALCUNI SERVER A DISPOSIZIONE

               BaseServer      Classe di base


               TCPServer       Classe per server TCP


               UDPServer       Classe per server UDP

Le sottoclassi ridefiniscono il modo di inizializzare il server
FUNZIONAMENTO DELL’HANDLER

•   Classe principale: BaseRequestHandler
• Il server accetta una connessione client e istanzia la classe
• Il costruttore di BaseRequestHandler:
      • imposta i parametri della connessione
        (indirizzo, socket del client, riferimento al server)
      • chiama nell’ordine:
            •   self.setup()
            •   self.handle()
            •   self.finish()
ESEMPIO 2
           Client                           Server
  collegamento al server           configurazione e avvio
     invio stringa di dati           attesa connessione
ricezione dei dati dal server    lettura dati inviati dal client
                                conversione dati in maiuscolo
                                 invio dati elaborati al client


        Stesso funzionamento dell’esempio 1
Ma implementazione del server fatta con SocketServer
ESEMPIO 2: SERVER
import SocketServer

HOST = ""	 	      # qualsiasi indirizzo disponibile sulla macchina che ospita il server
PORT = 10002	     # porta TCP sulla quale il server si mette in ascolto
SIZE = 1024	# numero di byte da leggere

class MyHandler(SocketServer.BaseRequestHandler):
	     """Gestore della connessione del client."""

	     def handle(self):
	     	     """Metodo da sovrascrivere per gestire la richiesta."""
	     	     print "Connessione da: %s:%d" % self.client_address

	     	     # lettura dei dati inviati dal client
	     	     data = self.request.recv(SIZE)
	     	     print "-->", data

	     	     # elaborazione dati ricevuti
	     	     data = data.upper()

	     	     # invio di dati al client
	     	     self.request.send(data)
	     	     print "<--", data

if __name__ == '__main__':
	     indirizzo = HOST, PORT
	     SocketServer.TCPServer.allow_reuse_address = True
	     server = SocketServer.TCPServer(indirizzo, MyHandler)
	     server.handle_request()
ESEMPIO 3

•   Server che comunica l’orario corrente al client
• Richiesti username e password per l’accesso ai servizi
• Il server controlla la coppia di dati e:
      • dati corretti:	

    invia l’orario corrente
      • dati sbagliati:	

   nega il servizio
ESEMPIO 3
         Client                      Server
collegamento al server        ricezione username
     invio username                invio ACK
      ricezione ACK           ricezione password
     invio password              autenticazione
ricezione risposta server              ...
           ...              recupero orario corrente
  conversione in float          invio orario al client
   stampa dell’orario
ESEMPIO 3: SERVER (1/2)
import SocketServer
import time

ADDRESS = "", 10003
SIZE = 1024

ACK = "x06"
USERNAME = "user"
PASSWORD = "pass"



class MyHandler(SocketServer.BaseRequestHandler):
	     def handle(self):
	     	     [... implementazione nella prossima slide ...]



if __name__ == '__main__':
	     SocketServer.TCPServer.allow_reuse_address = True
	     server = SocketServer.TCPServer(ADDRESS, MyHandler)
	     try:
	     	     server.serve_forever()
	     except KeyboardInterrupt:
	     	     print
	     	     server.socket.close()
ESEMPIO 3: SERVER (2/2)
[...]

class MyHandler(SocketServer.BaseRequestHandler):

	       def handle(self):
	       	     print "Connessione da: %s:%d" % self.client_address
	       	
	       	     username = self.request.recv(SIZE)	 # ricezione username
	       	     self.request.send(ACK)	 	     	     # invio ACK
	       	     password = self.request.recv(SIZE)	 # ricezione password

	       	    # autenticazione
	       	    if (username, password) == (USERNAME, PASSWORD):
	       	    	     # invio di dati al client
	       	    	     data = str(time.time())
	       	    	     self.request.send(data)
	       	    	     print "Orario corrente:", data
	       	    else:
	       	    	     # autenticazione fallita
	       	    	     print "Username/password errate"
	       	    print

[...]
ESEMPIO 3: CLIENT
import socket
import sys
import datetime

ADDRESS = "127.0.0.1", 10003
SIZE = 1024



if __name__ == '__main__':
	     # username e password passati come argomenti al programma
	     USERNAME = sys.argv[1]
	     PASSWORD = sys.argv[2]

	    print "Connessione verso %s:%d" % ADDRESS
	    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
	    s.connect(ADDRESS)

	    s.send(USERNAME)	 	       # invio username
	    s.recv(1)	 	      	       # ricezione ACK
	    s.send(PASSWORD)	 	       # invio password

	    data = s.recv(SIZE)
	    if data != "":
	    	     data = float(data)
	    	     print datetime.datetime.fromtimestamp(data)
	    	     print
	    else:
	    	     sys.exit("Servizio negaton")
HANDLER A DISPOSIZIONE

                         BaseRequestHandler




        StreamRequestHandler          DatagramRequestHandler




Le sottoclassi sovrascrivono setup() e finish()
GESTIONE CONNESSIONI
                           CONCORRENTI
• BaseServer gestisce le connessioni in modo sequenziale
• A disposizione vi sono due classi:
    •   ThreadingMixIn	

       	

 una connessione è associata a un thread
    •   ForkingMixIn	

   	

   una connessione è associata a un processo
SERVER CON SOTTOPROCESSI
                   ForkingMixIn              TCPServer




                                  MyServer


class MyServer(ForkingMixIn, TCPServer):
    [...
    server che crea un sottoprocesso per ogni connessione client
    ...]


   Comportamento specificato con il server, non con l’handler
ESEMPIO 4

•   Server che invia file al client
• Problema
  con file molto grandi e connessioni multiple
  la coda si può riempire e le connessioni vengono rifiutate
• Soluzione
  processi separati per gestire connessioni diverse
ESEMPIO 4
        Client                      Server
 collegamento al server       attesa connessione
invio nome file richiesto   creazione nuovo processo
ricezione dimensione file      ricezione nome file
       invio ACK             invio dimensione file
ricezione file dal server         ricezione ACK
                             invio del file richiesto
ESEMPIO 4: SERVER (1/2)
import SocketServer
import os

ADDRESS = "", 10004
SIZE = 1024



class MyHandler(SocketServer.BaseRequestHandler):
	     def handle(self):
	     	     [... implementazione nella prossima slide ...]



if __name__ == '__main__':
	     print "Server: %d" % os.getpid()
	     SocketServer.ForkingTCPServer.allow_reuse_address = True
	     server = SocketServer.ForkingTCPServer(ADDRESS, MyHandler)
	     try:
	     	     server.serve_forever()
	     except KeyboardInterrupt:
	     	     print
	     	     server.socket.close()
ESEMPIO 4: SERVER (2/2)
[...]

class MyHandler(SocketServer.BaseRequestHandler):

	       def handle(self):
	       	     print "Connessione da: %s:%d" % self.client_address
	       	     print "Processo: %d" % os.getpid()

	       	     # lettura nome file richiesto
	       	     path = self.request.recv(SIZE)

	       	     try:
	       	     	       # apertura file e lettura dati
	       	     	       data = open(path, "rb").read()

	       	     except OSError:
	       	     	     # file non trovato
	       	     	     self.request.send("0")

	       	     else:
	       	     	       total_size = len(data)
	       	     	       self.request.send(str(total_size))	 # invio dimensione file
	       	     	       self.request.recv(1)	   	     	     	     # ricezione ACK
	       	     	       self.request.send(data)		     	     # invio file

[...]
ESEMPIO 4: CLIENT
import socket
import sys

ADDRESS = "127.0.0.1", 10004
SIZE = 1024

ACK = "x06"

if __name__ == '__main__':
	     # nome del file da scaricare passato come argomento al programma
	     NAME = sys.argv[1]

	    print "Connessione verso %s:%d" % ADDRESS
	    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
	    s.connect(ADDRESS)

	    s.send(NAME)	     	     	     	     # nome del file da scaricare
	    total_size = int(s.recv(SIZE))	     # dimensione file
	    s.send(ACK)		     	     	     # invio ACK

	    # ciclo di ricezione dati
	    data = s.recv(SIZE)
	    while len(data) < total_size:
	    	     data += s.recv(SIZE)

	    print "Ricevuti %d byte" % len(data)
CASO D’USO: MODULO
  BASE HTTP SERVER
BaseHTTPServer    è costruito su SocketServer

     TCPServer               StreamRequestHandler




     HTTPServer             BaseHTTPRequestHandler
FUNZIONAMENTO DI
     BASE HTTP REQUEST HANDLER
•   Essendo una sottoclasse di StreamRequestHandler
    al socket sono associati due file:
      •   self.rfile	

   file aperto in lettura (ricezione di HTTP request)
      •   self.wfile	

   file aperto in scrittura (invio di HTTP response)
•   Definisce handle() per:
      • effettuare il parsing della HTTP request line
      • effettuare il parsing degli header
      • far proseguire l’elaborazione chiamando un metodo diverso in base all’HTTP
        method del messaggio ricevuto
LOGICA DI handle()
      handle() chiama un metodo di oggetto
  corrispondente all’HTTP method del messaggio

 HTTP method                  Metodo dell’handler
      GET                          do_GET()
      POST                         do_POST()
     OTHER                        do_OTHER()
      ...                             ...

Le sottoclassi devono implementare un metodo do_*
          per ogni HTTP method da gestire
ESEMPIO 5

• Server web che accetta comandi sh-like
• Il server legge il request URI del messaggio HTTP e ne estrae il
  comando
      • comando valido:	

 	

    	

 esegue il comando
        	

 	

 	

 	

 	

 	

   invia una risposta al client con il risultato
      • comando non valido:	

    invia una risposta di errore (400)
•   E.G. http://localhost/pwd → esegue il comando pwd
•   Implementazione del servizio nel metodo do_GET()
ESEMPIO 5: SERVER (1/2)
import BaseHTTPServer
import subprocess

ADDRESS = "", 10005

COMMANDS = "pwd", "ls", "uname", "date"



class MyHandler(BaseHTTPServer.BaseHTTPRequestHandler):
	     [... implementazione nella prossima slide ...]



if __name__ == '__main__':
	     server = BaseHTTPServer.HTTPServer(ADDRESS, MyHandler)
	     try:
	     	     server.serve_forever()
	     except KeyboardInterrupt:
	     	     print
	     	     server.socket.close()
ESEMPIO 5: SERVER (2/2)
[...]

class MyHandler(BaseHTTPServer.BaseHTTPRequestHandler):
	     """MyHandler non ridefinisce handle(), segue una logica di livello superiore.
	     """

	       def do_GET(self):
	       	     """Gestione degli HTTP request con HTTP method = GET"""
	       	     print "Connessione da: %s:%d" % self.client_address
	       	     print

	       	     # lettura del path per ricavare il comando
	       	     # primo carattere escluso: l’URI inizia con lo slash "/"
	       	     cmd = self.path[1:]

	       	     # controllo comando valido
	       	     if cmd in COMMANDS:
	       	     	     output = subprocess.Popen([cmd], stdout=subprocess.PIPE, shell=True).stdout.read()
	       	     	     self.send_response(200)
	       	     	     self.end_headers()
	       	     	     self.wfile.write(output)
	       	     else:
	       	     	     self.send_error(400)

[...]
ESEMPIO 5: CLIENT
• Come client può essere usato un browser qualsiasi
• Oppure si può usare il modulo urllib2
    import urllib2
    import sys

    ADDRESS = "127.0.0.1", 10005



    if __name__ == '__main__':
    	     # comando da eseguire passato come argomento al programma
    	     COMMAND = sys.argv[1]

    	    URI = "http://%s:%d/%s" % (ADDRESS[0], ADDRESS[1], COMMAND)
    	    print URI
    	    print

    	    try:
    	    	     r = urllib2.urlopen(URI)
    	    	     print "HTTP Status Code:", r.code
    	    	     print r.read()
    	    except urllib2.HTTPError as e:
    	    	     print e
PER SAPERNE DI PIÙ
•   Tanembaum, A. S (2003). Reti di calcolatori (IV ed.).
    Addison wesley
•   AA.VV. (2010). “socket – Low-level networking interface.”
    Sez. 17.2 in The Python Standard Library.
    Python v2.6.5, http://docs.python.org/library/socket.html
•   AA.VV. (2010). “SocketServer – A framework for network servers.”
    Sez. 20.17 in The Python Standard Library.
    Python v2.6.5, http://docs.python.org/library/socketserver.html
•   AA.VV. (2010). “BaseHTTPServer – Basic HTTP server.”
    Sez. 20.18 in The Python Standard Library.
    Python v2.6.5, http://docs.python.org/library/basehttpserver.html

Weitere ähnliche Inhalte

Ähnlich wie socket e SocketServer: il framework per i server Internet in Python

Sviluppo di servizi REST per Android - Luca Masini
Sviluppo di servizi REST per Android - Luca Masini Sviluppo di servizi REST per Android - Luca Masini
Sviluppo di servizi REST per Android - Luca Masini
Whymca
 
13 Linux Network Comandi
13 Linux Network Comandi13 Linux Network Comandi
13 Linux Network Comandi
Mauro Ferrigno
 
2 Protocolli Applicativi
2 Protocolli Applicativi2 Protocolli Applicativi
2 Protocolli Applicativi
acapone
 
Web Services Security
Web Services SecurityWeb Services Security
Web Services Security
peppespe
 
Analisi e prototipazione di un sistema di streaming per la localizzazione in ...
Analisi e prototipazione di un sistema di streaming per la localizzazione in ...Analisi e prototipazione di un sistema di streaming per la localizzazione in ...
Analisi e prototipazione di un sistema di streaming per la localizzazione in ...
TiborRacman
 
Analisi e prototipazione di un sistema di streaming per la localizzazione in ...
Analisi e prototipazione di un sistema di streaming per la localizzazione in ...Analisi e prototipazione di un sistema di streaming per la localizzazione in ...
Analisi e prototipazione di un sistema di streaming per la localizzazione in ...
TiborRacman
 

Ähnlich wie socket e SocketServer: il framework per i server Internet in Python (20)

Java lezione 9
Java lezione 9Java lezione 9
Java lezione 9
 
Simple Cloud API: accesso semplificato al cloud computing
Simple Cloud API: accesso semplificato al cloud computingSimple Cloud API: accesso semplificato al cloud computing
Simple Cloud API: accesso semplificato al cloud computing
 
Lezione 3: Connessioni TCP
Lezione 3: Connessioni TCPLezione 3: Connessioni TCP
Lezione 3: Connessioni TCP
 
Studio di una Architettura per un Sistema Distributivo ad Alta Affidabilità
Studio di una Architettura per un Sistema Distributivo ad Alta AffidabilitàStudio di una Architettura per un Sistema Distributivo ad Alta Affidabilità
Studio di una Architettura per un Sistema Distributivo ad Alta Affidabilità
 
Sviluppo di servizi REST per Android - Luca Masini
Sviluppo di servizi REST per Android - Luca Masini Sviluppo di servizi REST per Android - Luca Masini
Sviluppo di servizi REST per Android - Luca Masini
 
SVILUPPO DI SERVIZI REST PER ANDROID
SVILUPPO DI SERVIZI REST PER ANDROIDSVILUPPO DI SERVIZI REST PER ANDROID
SVILUPPO DI SERVIZI REST PER ANDROID
 
13 Linux Network Comandi
13 Linux Network Comandi13 Linux Network Comandi
13 Linux Network Comandi
 
SQL Saturday 2019 - Event Processing with Spark
SQL Saturday 2019 - Event Processing with SparkSQL Saturday 2019 - Event Processing with Spark
SQL Saturday 2019 - Event Processing with Spark
 
2 Protocolli Applicativi
2 Protocolli Applicativi2 Protocolli Applicativi
2 Protocolli Applicativi
 
Soluzioni per la difesa da attacchi DoS nelle reti SDN
Soluzioni per la difesa da attacchi DoS nelle reti SDNSoluzioni per la difesa da attacchi DoS nelle reti SDN
Soluzioni per la difesa da attacchi DoS nelle reti SDN
 
Web Services Security
Web Services SecurityWeb Services Security
Web Services Security
 
Analisi e prototipazione di un sistema di streaming per la localizzazione in ...
Analisi e prototipazione di un sistema di streaming per la localizzazione in ...Analisi e prototipazione di un sistema di streaming per la localizzazione in ...
Analisi e prototipazione di un sistema di streaming per la localizzazione in ...
 
Basi Di Dati 05
Basi Di Dati 05Basi Di Dati 05
Basi Di Dati 05
 
Introduzione ai protocolli tcp/ip ed al Domain Name System
Introduzione ai protocolli tcp/ip ed al Domain Name SystemIntroduzione ai protocolli tcp/ip ed al Domain Name System
Introduzione ai protocolli tcp/ip ed al Domain Name System
 
Analisi e prototipazione di un sistema di streaming per la localizzazione in ...
Analisi e prototipazione di un sistema di streaming per la localizzazione in ...Analisi e prototipazione di un sistema di streaming per la localizzazione in ...
Analisi e prototipazione di un sistema di streaming per la localizzazione in ...
 
Introduzione a node.js
Introduzione a node.jsIntroduzione a node.js
Introduzione a node.js
 
Introduzione a Node.js
Introduzione a Node.jsIntroduzione a Node.js
Introduzione a Node.js
 
[Laravel Day 2022] Deploy di Laravel su AWS Lambda (from Zero to Hero).pdf
[Laravel Day 2022] Deploy di Laravel su AWS Lambda (from Zero to Hero).pdf[Laravel Day 2022] Deploy di Laravel su AWS Lambda (from Zero to Hero).pdf
[Laravel Day 2022] Deploy di Laravel su AWS Lambda (from Zero to Hero).pdf
 
Progetto su iPhone - Seminario di Reti Wireless
Progetto su iPhone - Seminario di Reti WirelessProgetto su iPhone - Seminario di Reti Wireless
Progetto su iPhone - Seminario di Reti Wireless
 
AAI
AAI AAI
AAI
 

Mehr von PyCon Italia

Feed back report 2010
Feed back report 2010Feed back report 2010
Feed back report 2010
PyCon Italia
 
zc.buildout: "Un modo estremamente civile per sviluppare un'applicazione"
zc.buildout: "Un modo estremamente civile per sviluppare un'applicazione"zc.buildout: "Un modo estremamente civile per sviluppare un'applicazione"
zc.buildout: "Un modo estremamente civile per sviluppare un'applicazione"
PyCon Italia
 
Python: ottimizzazione numerica algoritmi genetici
Python: ottimizzazione numerica algoritmi geneticiPython: ottimizzazione numerica algoritmi genetici
Python: ottimizzazione numerica algoritmi genetici
PyCon Italia
 
PyCuda: Come sfruttare la potenza delle schede video nelle applicazioni python
PyCuda: Come sfruttare la potenza delle schede video nelle applicazioni pythonPyCuda: Come sfruttare la potenza delle schede video nelle applicazioni python
PyCuda: Come sfruttare la potenza delle schede video nelle applicazioni python
PyCon Italia
 
OpenERP e l'arte della gestione aziendale con Python
OpenERP e l'arte della gestione aziendale con PythonOpenERP e l'arte della gestione aziendale con Python
OpenERP e l'arte della gestione aziendale con Python
PyCon Italia
 
New and improved: Coming changes to the unittest module
 	 New and improved: Coming changes to the unittest module 	 New and improved: Coming changes to the unittest module
New and improved: Coming changes to the unittest module
PyCon Italia
 
Monitoraggio del Traffico di Rete Usando Python ed ntop
Monitoraggio del Traffico di Rete Usando Python ed ntopMonitoraggio del Traffico di Rete Usando Python ed ntop
Monitoraggio del Traffico di Rete Usando Python ed ntop
PyCon Italia
 
Crogioli, alambicchi e beute: dove mettere i vostri dati.
Crogioli, alambicchi e beute: dove mettere i vostri dati.Crogioli, alambicchi e beute: dove mettere i vostri dati.
Crogioli, alambicchi e beute: dove mettere i vostri dati.
PyCon Italia
 
Comet web applications with Python, Django & Orbited
Comet web applications with Python, Django & OrbitedComet web applications with Python, Django & Orbited
Comet web applications with Python, Django & Orbited
PyCon Italia
 

Mehr von PyCon Italia (20)

Feed back report 2010
Feed back report 2010Feed back report 2010
Feed back report 2010
 
Spyppolare o non spyppolare
Spyppolare o non spyppolareSpyppolare o non spyppolare
Spyppolare o non spyppolare
 
zc.buildout: "Un modo estremamente civile per sviluppare un'applicazione"
zc.buildout: "Un modo estremamente civile per sviluppare un'applicazione"zc.buildout: "Un modo estremamente civile per sviluppare un'applicazione"
zc.buildout: "Un modo estremamente civile per sviluppare un'applicazione"
 
Undici anni di lavoro con Python
Undici anni di lavoro con PythonUndici anni di lavoro con Python
Undici anni di lavoro con Python
 
Qt mobile PySide bindings
Qt mobile PySide bindingsQt mobile PySide bindings
Qt mobile PySide bindings
 
Python: ottimizzazione numerica algoritmi genetici
Python: ottimizzazione numerica algoritmi geneticiPython: ottimizzazione numerica algoritmi genetici
Python: ottimizzazione numerica algoritmi genetici
 
Python idiomatico
Python idiomaticoPython idiomatico
Python idiomatico
 
Python in the browser
Python in the browserPython in the browser
Python in the browser
 
PyPy 1.2: snakes never crawled so fast
PyPy 1.2: snakes never crawled so fastPyPy 1.2: snakes never crawled so fast
PyPy 1.2: snakes never crawled so fast
 
PyCuda: Come sfruttare la potenza delle schede video nelle applicazioni python
PyCuda: Come sfruttare la potenza delle schede video nelle applicazioni pythonPyCuda: Come sfruttare la potenza delle schede video nelle applicazioni python
PyCuda: Come sfruttare la potenza delle schede video nelle applicazioni python
 
OpenERP e l'arte della gestione aziendale con Python
OpenERP e l'arte della gestione aziendale con PythonOpenERP e l'arte della gestione aziendale con Python
OpenERP e l'arte della gestione aziendale con Python
 
New and improved: Coming changes to the unittest module
 	 New and improved: Coming changes to the unittest module 	 New and improved: Coming changes to the unittest module
New and improved: Coming changes to the unittest module
 
Monitoraggio del Traffico di Rete Usando Python ed ntop
Monitoraggio del Traffico di Rete Usando Python ed ntopMonitoraggio del Traffico di Rete Usando Python ed ntop
Monitoraggio del Traffico di Rete Usando Python ed ntop
 
Jython for embedded software validation
Jython for embedded software validationJython for embedded software validation
Jython for embedded software validation
 
Foxgame introduzione all'apprendimento automatico
Foxgame introduzione all'apprendimento automaticoFoxgame introduzione all'apprendimento automatico
Foxgame introduzione all'apprendimento automatico
 
Effective EC2
Effective EC2Effective EC2
Effective EC2
 
Django è pronto per l'Enterprise
Django è pronto per l'EnterpriseDjango è pronto per l'Enterprise
Django è pronto per l'Enterprise
 
Crogioli, alambicchi e beute: dove mettere i vostri dati.
Crogioli, alambicchi e beute: dove mettere i vostri dati.Crogioli, alambicchi e beute: dove mettere i vostri dati.
Crogioli, alambicchi e beute: dove mettere i vostri dati.
 
Comet web applications with Python, Django & Orbited
Comet web applications with Python, Django & OrbitedComet web applications with Python, Django & Orbited
Comet web applications with Python, Django & Orbited
 
Cleanup and new optimizations in WPython 1.1
Cleanup and new optimizations in WPython 1.1Cleanup and new optimizations in WPython 1.1
Cleanup and new optimizations in WPython 1.1
 

socket e SocketServer: il framework per i server Internet in Python

  • 1. SOCKET E SOCKETSERVER IL FRAMEWORK PER I SERVER INTERNET IN PYTHON Marco Spisto, Giovanni Bajo PyCon Italia Quattro Firenze, 9 maggio 2010
  • 2. SOMMARIO • Servizi di rete con Python • Modulo di basso livello: socket • Modulo di alto livello: SocketServer • Struttura del modulo • Classi per il server • Classi per la gestione della connessione client • Gestione concorrente delle richieste • Caso d’uso: il server HTTP della libreria standard
  • 3. SERVIZI DI RETE CON PYTHON • Basso livello: socket Wrapper per il modulo implementato in C • Alto livello: SocketServer Framework costruito sul modulo socket
  • 4. OGGETTI SOCKET • Costruttore socket(family, type) • family famiglia di indirizzi di rete (e.g.: IPv4) • type tipo di trasporto dati (e.g.: stream, datagrammi) • Metodi per la comunicazione • mysocket.recv(n_bytes) ricezione (lettura) di al più n_bytes • mysocket.send(data) invio della stringa data
  • 5. ESEMPIO 1 Client Server collegamento al server configurazione e avvio invio stringa di dati attesa connessione ricezione dei dati dal server lettura dati inviati dal client conversione dati in maiuscolo invio dati elaborati al client
  • 6. ESEMPIO 1: SERVER import socket HOST = "" # qualsiasi indirizzo disponibile sulla macchina che ospita il server PORT = 10001 # porta TCP sulla quale il server si mette in ascolto SIZE = 1024 # numero di byte da leggere def start(indirizzo): def handle(connection): # creazione del socket request, address = connection s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) print "Connessione da: %s:%d" % address # configurazione # lettura dei dati inviati dal client s.bind(indirizzo) data = request.recv(SIZE) s.listen(5) print "-->", data # attesa connessione # elaborazione dati ricevuti client = s.accept() data = data.upper() # gestione connessione # invio di dati al client handle(client) request.send(data) print "<--", data # chiusura socket s.close() if __name__ == '__main__': indirizzo = HOST, PORT start(indirizzo)
  • 7. ESEMPIO 1: CLIENT import socket HOST = "127.0.0.1" # indirizzo IPv4 della macchina che ospita il server PORT = 10001 # porta TCP sulla quale il server si mette in ascolto SIZE = 1024 # numero di byte da leggere if __name__ == '__main__': indirizzo = HOST, PORT print "Connessione verso %s:%d" % indirizzo s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.connect(indirizzo) data = "ciao" print "-->", data s.send(data) data = s.recv(SIZE) print "<--", data
  • 8. MODULO SOCKETSERVER Strutturato con due classi principali Server Handler Implementazione Gestione servizio client N.B. in Python 3 il modulo si chiamerà socketserver
  • 9. FUNZIONAMENTO DEL SERVER • Classe principale: BaseServer • Costruttore: BaseServer(address, HandlerFactory) • address coppia: indirizzo, porta • HandlerFactory classe che viene istanziata per gestire una singola connessione con il client • Metodi di controllo: • handle_request() accettazione singola connessione • serve_forever() ciclo (infinito) di accettazione connessioni
  • 10. ALCUNI SERVER A DISPOSIZIONE BaseServer Classe di base TCPServer Classe per server TCP UDPServer Classe per server UDP Le sottoclassi ridefiniscono il modo di inizializzare il server
  • 11. FUNZIONAMENTO DELL’HANDLER • Classe principale: BaseRequestHandler • Il server accetta una connessione client e istanzia la classe • Il costruttore di BaseRequestHandler: • imposta i parametri della connessione (indirizzo, socket del client, riferimento al server) • chiama nell’ordine: • self.setup() • self.handle() • self.finish()
  • 12. ESEMPIO 2 Client Server collegamento al server configurazione e avvio invio stringa di dati attesa connessione ricezione dei dati dal server lettura dati inviati dal client conversione dati in maiuscolo invio dati elaborati al client Stesso funzionamento dell’esempio 1 Ma implementazione del server fatta con SocketServer
  • 13. ESEMPIO 2: SERVER import SocketServer HOST = "" # qualsiasi indirizzo disponibile sulla macchina che ospita il server PORT = 10002 # porta TCP sulla quale il server si mette in ascolto SIZE = 1024 # numero di byte da leggere class MyHandler(SocketServer.BaseRequestHandler): """Gestore della connessione del client.""" def handle(self): """Metodo da sovrascrivere per gestire la richiesta.""" print "Connessione da: %s:%d" % self.client_address # lettura dei dati inviati dal client data = self.request.recv(SIZE) print "-->", data # elaborazione dati ricevuti data = data.upper() # invio di dati al client self.request.send(data) print "<--", data if __name__ == '__main__': indirizzo = HOST, PORT SocketServer.TCPServer.allow_reuse_address = True server = SocketServer.TCPServer(indirizzo, MyHandler) server.handle_request()
  • 14. ESEMPIO 3 • Server che comunica l’orario corrente al client • Richiesti username e password per l’accesso ai servizi • Il server controlla la coppia di dati e: • dati corretti: invia l’orario corrente • dati sbagliati: nega il servizio
  • 15. ESEMPIO 3 Client Server collegamento al server ricezione username invio username invio ACK ricezione ACK ricezione password invio password autenticazione ricezione risposta server ... ... recupero orario corrente conversione in float invio orario al client stampa dell’orario
  • 16. ESEMPIO 3: SERVER (1/2) import SocketServer import time ADDRESS = "", 10003 SIZE = 1024 ACK = "x06" USERNAME = "user" PASSWORD = "pass" class MyHandler(SocketServer.BaseRequestHandler): def handle(self): [... implementazione nella prossima slide ...] if __name__ == '__main__': SocketServer.TCPServer.allow_reuse_address = True server = SocketServer.TCPServer(ADDRESS, MyHandler) try: server.serve_forever() except KeyboardInterrupt: print server.socket.close()
  • 17. ESEMPIO 3: SERVER (2/2) [...] class MyHandler(SocketServer.BaseRequestHandler): def handle(self): print "Connessione da: %s:%d" % self.client_address username = self.request.recv(SIZE) # ricezione username self.request.send(ACK) # invio ACK password = self.request.recv(SIZE) # ricezione password # autenticazione if (username, password) == (USERNAME, PASSWORD): # invio di dati al client data = str(time.time()) self.request.send(data) print "Orario corrente:", data else: # autenticazione fallita print "Username/password errate" print [...]
  • 18. ESEMPIO 3: CLIENT import socket import sys import datetime ADDRESS = "127.0.0.1", 10003 SIZE = 1024 if __name__ == '__main__': # username e password passati come argomenti al programma USERNAME = sys.argv[1] PASSWORD = sys.argv[2] print "Connessione verso %s:%d" % ADDRESS s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.connect(ADDRESS) s.send(USERNAME) # invio username s.recv(1) # ricezione ACK s.send(PASSWORD) # invio password data = s.recv(SIZE) if data != "": data = float(data) print datetime.datetime.fromtimestamp(data) print else: sys.exit("Servizio negaton")
  • 19. HANDLER A DISPOSIZIONE BaseRequestHandler StreamRequestHandler DatagramRequestHandler Le sottoclassi sovrascrivono setup() e finish()
  • 20. GESTIONE CONNESSIONI CONCORRENTI • BaseServer gestisce le connessioni in modo sequenziale • A disposizione vi sono due classi: • ThreadingMixIn una connessione è associata a un thread • ForkingMixIn una connessione è associata a un processo
  • 21. SERVER CON SOTTOPROCESSI ForkingMixIn TCPServer MyServer class MyServer(ForkingMixIn, TCPServer): [... server che crea un sottoprocesso per ogni connessione client ...] Comportamento specificato con il server, non con l’handler
  • 22. ESEMPIO 4 • Server che invia file al client • Problema con file molto grandi e connessioni multiple la coda si può riempire e le connessioni vengono rifiutate • Soluzione processi separati per gestire connessioni diverse
  • 23. ESEMPIO 4 Client Server collegamento al server attesa connessione invio nome file richiesto creazione nuovo processo ricezione dimensione file ricezione nome file invio ACK invio dimensione file ricezione file dal server ricezione ACK invio del file richiesto
  • 24. ESEMPIO 4: SERVER (1/2) import SocketServer import os ADDRESS = "", 10004 SIZE = 1024 class MyHandler(SocketServer.BaseRequestHandler): def handle(self): [... implementazione nella prossima slide ...] if __name__ == '__main__': print "Server: %d" % os.getpid() SocketServer.ForkingTCPServer.allow_reuse_address = True server = SocketServer.ForkingTCPServer(ADDRESS, MyHandler) try: server.serve_forever() except KeyboardInterrupt: print server.socket.close()
  • 25. ESEMPIO 4: SERVER (2/2) [...] class MyHandler(SocketServer.BaseRequestHandler): def handle(self): print "Connessione da: %s:%d" % self.client_address print "Processo: %d" % os.getpid() # lettura nome file richiesto path = self.request.recv(SIZE) try: # apertura file e lettura dati data = open(path, "rb").read() except OSError: # file non trovato self.request.send("0") else: total_size = len(data) self.request.send(str(total_size)) # invio dimensione file self.request.recv(1) # ricezione ACK self.request.send(data) # invio file [...]
  • 26. ESEMPIO 4: CLIENT import socket import sys ADDRESS = "127.0.0.1", 10004 SIZE = 1024 ACK = "x06" if __name__ == '__main__': # nome del file da scaricare passato come argomento al programma NAME = sys.argv[1] print "Connessione verso %s:%d" % ADDRESS s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.connect(ADDRESS) s.send(NAME) # nome del file da scaricare total_size = int(s.recv(SIZE)) # dimensione file s.send(ACK) # invio ACK # ciclo di ricezione dati data = s.recv(SIZE) while len(data) < total_size: data += s.recv(SIZE) print "Ricevuti %d byte" % len(data)
  • 27. CASO D’USO: MODULO BASE HTTP SERVER BaseHTTPServer è costruito su SocketServer TCPServer StreamRequestHandler HTTPServer BaseHTTPRequestHandler
  • 28. FUNZIONAMENTO DI BASE HTTP REQUEST HANDLER • Essendo una sottoclasse di StreamRequestHandler al socket sono associati due file: • self.rfile file aperto in lettura (ricezione di HTTP request) • self.wfile file aperto in scrittura (invio di HTTP response) • Definisce handle() per: • effettuare il parsing della HTTP request line • effettuare il parsing degli header • far proseguire l’elaborazione chiamando un metodo diverso in base all’HTTP method del messaggio ricevuto
  • 29. LOGICA DI handle() handle() chiama un metodo di oggetto corrispondente all’HTTP method del messaggio HTTP method Metodo dell’handler GET do_GET() POST do_POST() OTHER do_OTHER() ... ... Le sottoclassi devono implementare un metodo do_* per ogni HTTP method da gestire
  • 30. ESEMPIO 5 • Server web che accetta comandi sh-like • Il server legge il request URI del messaggio HTTP e ne estrae il comando • comando valido: esegue il comando invia una risposta al client con il risultato • comando non valido: invia una risposta di errore (400) • E.G. http://localhost/pwd → esegue il comando pwd • Implementazione del servizio nel metodo do_GET()
  • 31. ESEMPIO 5: SERVER (1/2) import BaseHTTPServer import subprocess ADDRESS = "", 10005 COMMANDS = "pwd", "ls", "uname", "date" class MyHandler(BaseHTTPServer.BaseHTTPRequestHandler): [... implementazione nella prossima slide ...] if __name__ == '__main__': server = BaseHTTPServer.HTTPServer(ADDRESS, MyHandler) try: server.serve_forever() except KeyboardInterrupt: print server.socket.close()
  • 32. ESEMPIO 5: SERVER (2/2) [...] class MyHandler(BaseHTTPServer.BaseHTTPRequestHandler): """MyHandler non ridefinisce handle(), segue una logica di livello superiore. """ def do_GET(self): """Gestione degli HTTP request con HTTP method = GET""" print "Connessione da: %s:%d" % self.client_address print # lettura del path per ricavare il comando # primo carattere escluso: l’URI inizia con lo slash "/" cmd = self.path[1:] # controllo comando valido if cmd in COMMANDS: output = subprocess.Popen([cmd], stdout=subprocess.PIPE, shell=True).stdout.read() self.send_response(200) self.end_headers() self.wfile.write(output) else: self.send_error(400) [...]
  • 33. ESEMPIO 5: CLIENT • Come client può essere usato un browser qualsiasi • Oppure si può usare il modulo urllib2 import urllib2 import sys ADDRESS = "127.0.0.1", 10005 if __name__ == '__main__': # comando da eseguire passato come argomento al programma COMMAND = sys.argv[1] URI = "http://%s:%d/%s" % (ADDRESS[0], ADDRESS[1], COMMAND) print URI print try: r = urllib2.urlopen(URI) print "HTTP Status Code:", r.code print r.read() except urllib2.HTTPError as e: print e
  • 34. PER SAPERNE DI PIÙ • Tanembaum, A. S (2003). Reti di calcolatori (IV ed.). Addison wesley • AA.VV. (2010). “socket – Low-level networking interface.” Sez. 17.2 in The Python Standard Library. Python v2.6.5, http://docs.python.org/library/socket.html • AA.VV. (2010). “SocketServer – A framework for network servers.” Sez. 20.17 in The Python Standard Library. Python v2.6.5, http://docs.python.org/library/socketserver.html • AA.VV. (2010). “BaseHTTPServer – Basic HTTP server.” Sez. 20.18 in The Python Standard Library. Python v2.6.5, http://docs.python.org/library/basehttpserver.html