Home > python > python: socket per programmatori di coccio

python: socket per programmatori di coccio

27 Maggio 2011

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
&#91;/sourcecode&#93;

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
&#91;sourcecode lang="python"&#93;
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
&#91;/sourcecode&#93;
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:
&#91;sourcecode lang="css"&#93;
server_socket.bind((host, port))
&#91;/sourcecode&#93;

Nota:
Se volessimo rendere visibile il socket dall'esterno utilizzeremmo gethostname() 
&#91;sourcecode lang="python"&#93;
server_socket.bind((server_socket.gethostname(), port))
&#91;/sourcecode&#93;

Mettiamo ora il socket (lato server) in ascolto:
&#91;sourcecode lang="python"&#93;
server_socket.listen(5)
&#91;/sourcecode&#93;
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():
&#91;sourcecode lang="python"&#93;
while True:
    client_socket, address = server_socket.accept()
    ...
&#91;/sourcecode&#93;
dopodichè, con il secondo ciclo annidato, 
&#91;sourcecode lang="python"&#93;
    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
&#91;/sourcecode&#93;
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:
&#91;sourcecode lang="python"&#93;
# 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
&#91;/sourcecode&#93;

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:
&#91;sourcecode lang="python"&#93;
        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

Categorie:python Tag:
I commenti sono chiusi.