python: socket per programmatori di coccio
Essendo io stesso un programmatore di coccio,
ho cercato di mettere insieme un po’ di informazioni
trovate in rete riguardanti i sockets.
Ovviamente si trova tutto sulla doc ufficiale di python e
sulla libreria di riferimento.
Mi piacevano però alcuni esempi, che posterò qui come promemoria.
Alcune delle “cose importanti” da sapere sono che:
– Il socket rappresenta la forma più usata di comunicazione
tra processi (IPC)
– Nella maggiorparte dei casi un non-programmatore come me
utilizzerà sockets di tipo STREAM su indirizzi e protocolli INET.
– se il socket non verrà trattato come un file (con metodi read
e write), i metodi saranno send() e recv(), rispettivamente per
spedire e ricevere un messaggio.
– se recv() restituisce 0 byte, significa che è caduta la connessione
dall’altra parte
Ecco un esempio semplice per il “lato server”:
# myserver.py import socket port = 4000 host = "" server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) server_socket.bind((host, port)) server_socket.listen(5) print "Type 'Q' or 'q' to QUIT" print "Server Waiting for client on port ", port while True: client_socket, address = server_socket.accept() print "Connection from ", address while True: server_data = raw_input("--> server: ") if server_data.lower() == 'q': client_socket.send(server_data) client_socket.close() break else: client_socket.send(server_data) client_data = client_socket.recv(1024) if client_data.lower() == 'q': print "Quit from client" client_socket.close() break else: print "<-- client: ", client_data break [/sourcecode] In sostanza: Scegliamo una porta di comunicazione. Scegliamo l'host server che può essere, per esperimenti in locale "", "localhost", "127.0.0.1". Creiamo l'oggetto socket [sourcecode lang="python"] server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) [/sourcecode] dove AF_INET rappresenta il protocollo TCP/IP con indirizzo ip IPv4 e SOCK_STREAM è il tipo di socket. Leghiamo il socket, tramite bind() all'host e porta appena definiti: [sourcecode lang="css"] server_socket.bind((host, port)) [/sourcecode] Nota: Se volessimo rendere visibile il socket dall'esterno utilizzeremmo gethostname() [sourcecode lang="python"] server_socket.bind((server_socket.gethostname(), port)) [/sourcecode] Mettiamo ora il socket (lato server) in ascolto: [sourcecode lang="python"] server_socket.listen(5) [/sourcecode] creando successivamente 2 cicli while annidati, con il primo accettiamo le connessioni dal client e ne associamo socket ed indirizzo alle variabili client_socket e address grazie ad accept(): [sourcecode lang="python"] while True: client_socket, address = server_socket.accept() ... [/sourcecode] dopodichè, con il secondo ciclo annidato, [sourcecode lang="python"] while True: server_data = raw_input("--> server: ") if server_data.lower() == 'q': client_socket.send(server_data) client_socket.close() break else: client_socket.send(server_data)
creo il messaggio tramite raw_input().
Tramite if, nel caso venga digitato ‘q’, spedisco comunque
il messaggio per avere un riscontro lato-client, dopodichè
chiudo la connessione.
Allo stesso modo, se ho passato l’if precedente senza chiudere
la connessione, essendo in ascolto, nel caso il client abbia
spedito un messaggio, lo ricevo tramite recv() e lo associo alla
variabile client_data:
client_data = client_socket.recv(1024) if client_data.lower() == 'q': print "Quit from client" client_socket.close() break else: print "<-- client: ", client_data [/sourcecode] se (come vedremo dal codice client) dovesse essere arrivato un quit ('q'), chiudiamo il socket ed usciamo dal ciclo con un break. Altrimenti stampo a video il messaggio. In caso di quit dal client, il break ci farebbe uscire dal while annidato e per uscire dal while principale, siccome non voglio che il socket rimanga su, uso un altro break. Ora analizziamo il lato client: [sourcecode lang="python"] # myclient.py import socket port = 4000 host_server = "localhost" client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) client_socket.connect((host_server, port)) print "Type 'Q' or 'q' to QUIT" while True: server_data = client_socket.recv(1024) if server_data.lower() == 'q': print "Quit from server" client_socket.close() break else: print "<-- server: ", server_data client_data = raw_input("--> client: ") if client_data.lower() != 'q': client_socket.send(client_data) else: client_socket.send(client_data) client_socket.close() break
Si definiscono porta (la stessa dove il socket_server
è in ascolto, ovvio) e address del socket server.
Si crea l’oggetto socket e lo si connette con il metodo
connect():
client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) client_socket.connect((host_server, port))
Si crea il solito loop dove mettiamo il socket immediatamente
in ricezione tramite recv():
while True: server_data = client_socket.recv(1024)
Effettuo il test di controllo per verificare che il server_socket
non abbia chiuso la connessione.
if server_data.lower() == 'q': print "Quit from server" client_socket.close() break else: print "<-- server: ", server_data [/sourcecode] Se il lato server non ha effettuato il quit (else), stampo a video il messaggio e, subito dopo, creo il messaggio lato client da spedire al server: [sourcecode lang="python"] client_data = raw_input("--> client: ")
Nonostante il messaggio venga comunque spedito al lato
server, effettuo un test di controllo, per chiudere la
connessione nel caso venga digitato ‘q’.
Come visto precedentemente, tale messaggio viene spedito
ugualmente in modo che venga sottoposto a test di controllo
anche nel lato server.
Link utili:
Doc ufficiale di python
Socket Programming Howto
Libreria di riferimento di Python (socket)
altro materiale de coccio:
decoratori
pattern observer
pattern mvc
Commenti recenti