Proviamo a realizzare questo semplice esercizio: vorrei avere un server ed un client che possano comunicare tramite socket, in modo tale che il client possa richiedere al server dei dati, il server preleverà tali dati da un database MySQL e li invierà al client.
Lo schema dell’esercizio è approssimativamente questo:
Per svolgere l’esercizio utilizzerò un database con una tabella clienti costruita nel modo seguente:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 |
-- -- Struttura della tabella `clienti` -- CREATE TABLE `clienti` ( `id` int(255) NOT NULL, `nome` varchar(100) NOT NULL, `indirizzo` varchar(1024) NOT NULL, `telefono` varchar(100) NOT NULL, `agente` int(255) NOT NULL ) ENGINE=InnoDB DEFAULT CHARSET=latin1; -- -- Dump dei dati per la tabella `clienti` -- INSERT INTO `clienti` (`id`, `nome`, `indirizzo`, `telefono`, `agente`) VALUES (1, 'Mario Rossi', 'Via Roma 1', '00569865', 3), (2, 'Luigi Verdi', 'Via Milano 12', '00495233', 3), (3, 'Gianni Bianchi', 'Via Genova 123', '00683581', 3), (4, 'Chiara Rossi', 'Via Pescara 54', '00401299', 2), (5, 'Luisa Neri', 'Via Ottima 77', '00279150', 3), (6, 'Giovanni Celesti', 'Via Belli 16', '00515977', 2), (7, 'Marco Bruni', 'Via Neri 10', '00161097', 3), (8, 'Sergio Sereni', 'Via Savona 15', '00121871', 2), (9, 'Paolo Lumi', 'Via Novara 19', '00554018', 3), (10, 'Paola Neri', 'Via Padova 199', '00249472', 3), (11, 'Pietro Chiari', 'Via Pietra 290', '00600550', 2), (12, 'Fabio Rossi', 'Via Venezia 2', '00270185', 2), (13, 'Giuseppe Blandi', 'Via Napoli 8', '00462208', 3), (14, 'Aldo Valdi', 'Via Vesuvio 200', '00572389', 2), (15, 'Piero Storni', 'Via Otranto 9', '00278110', 3), (16, 'Luigi L\'Avigno', 'Via Dell\'Altro', '055123456', 3), (17, 'Luigi L\'Avigno', 'Via Dell\'Altro', '055123456', 3); -- -- Indici per le tabelle scaricate -- -- -- Indici per le tabelle `clienti` -- ALTER TABLE `clienti` ADD PRIMARY KEY (`id`); -- -- AUTO_INCREMENT per le tabelle scaricate -- -- -- AUTO_INCREMENT per la tabella `clienti` -- ALTER TABLE `clienti` MODIFY `id` int(255) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=18;COMMIT; |
In aggiunta utilizzerò una classe MySQLdb personalizzata, sviluppata nel modo seguente e messa nel file database.py:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
import mysql.connector class MySQLdb(): def __init__(s,dbhost,dbuser,dbpass,dbname): s.__dbhost = dbhost s.__dbuser = dbuser s.__dbpass = dbpass s.__dbname = dbname s.__db = None s.connect() def connect(s): s.__db = mysql.connector.connect( host = s.__dbhost, user = s.__dbuser, passwd = s.__dbpass, database = s.__dbname ) def In(s,sql,*vals): cursor = s.__db.cursor() cursor.execute(sql,vals) s.__db.commit() return cursor.lastrowid def Out(s,sql,*vals): cursor = s.__db.cursor(dictionary=True) cursor.execute(sql,vals) result = cursor.fetchall() return result def __del__(s): s.__db.close() |
La cartella dell’intero progetto sarà organizzata nella maniera seguente:
client.py
librerie
└── database.py
└── __init__.py
server.py
Fatte queste premesse andiamo anzitutto a creare il nostro file server.py. Nel codice ho inserito i commenti ai vari passaggi:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 |
from librerie.database import MySQLdb import socket #indirizzo di connessione HOST = '127.0.0.1' PORT = 8100 #con questa funzione estraiamo i dati def estrai_dati(): #colleghiamoci al database mysql = MySQLdb("localhost","root","","torregatti") #leggiamo tutti i clienti clienti = mysql.Out("SELECT * FROM clienti") #impostiamo una variabile, che alla fine restituiremo, su vuoto risultato = "" #leggiamo tutti i clienti for c in clienti: #aggiungiamo ciascun cliente ad una stringa risultato += "%s\t%s\t\t%s\n" % (c["id"],c["nome"],c["telefono"]) return risultato #creiamo la connessione al socket #con AF_INET usiamo il protocollo TCP/IPv4 #SOCK_STREAM tipo di socket, l'unico veramente utile con SOCK_DGRAM s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) #mettiamoci in ascolto sull'indirizzo locale e la porta scelta s.bind((HOST, PORT)) s.listen(1) # 1 = numero massimo di connessioni in coda #avviamo il ciclo di ascolto e chiamata print "server avviato..." while True: #mettiamo in attesa di connessione conn, addr = s.accept() #per avviare la lettura ci aspettiamo il codice LEGGI7711 #non usiamo il ciclo while visto che il codice non supera i 1024Byte codice = conn.recv(1024) #se il codice e' giusto inviamo i dati del db if codice == "LEGGI7711": print "invio dati a", addr conn.sendall(estrai_dati()) conn.close() #in caso di codice = CHIUDI chiudiamo il server if codice == "CHIUDI": print "chiudo server..." break s.close() print "server chiuso" |
Adesso è il momento del client.py.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 |
import socket #indirizzo di connessione, lo stesso del server HOST = '127.0.0.1' PORT = 8100 #dichiaro alcune variabili che potro' usare dopo #nel menu di scelta, senza dover scrivere le opzioni da le virgolette s = S = True n = N = False esci = -1 chiudi = -2 #iniziamo il ciclo di programma while True: #controlliamo che non ci siano errori try: print "Leggi? (s/n/esci/chiudi): ", scelta = input() if scelta == esci: break if scelta: #colleghiamoci al socket s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.connect((HOST,PORT)) # INVIO IL CODICE AL SERVER s.sendall("LEGGI7711") #leggiamo qello che ci restituisce data = s.recv(1024) s.close() print data else: print "Lettura saltata" if scelta == chiudi: s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.connect((HOST,PORT)) # INVIO IL RICHIESTA CHIUSURA SERVER s.sendall("CHIUDI") s.close() #in caso di lettera o carattere non codificato except NameError: print "Opzione non valida" #in caso di pressione di invio except SyntaxError: print "Opzione non valida" |
I risultati che dovremmo vedere sono rispettivamente:
1. Per il server vedo quando è stato avviato, da dove e da quale porta
2. Sul client vedo l’elenco presente sul database.