42
Scuola Politecnica e delle Scienze di Base Corso di Laurea in Ingegneria Informatica Elaborato finale in PROGRAMMAZIONE I Programmazione di applicazioni Client- Server in un linguaggio interpretato: Python Anno Accademico 2015/2016 Candidato: Mickael Di Carluccio matr. N46000541

Programmazione di applicazioni Client- Server in un ... · Capitolo1. Python 4.Svilupposoftware: Esistonoinnumerevoliaspettilegatiallosvilupposoftware,chepossonoaiuta-reognisviluppatoreadiventareunprogrammatoremigliore

  • Upload
    ngoanh

  • View
    219

  • Download
    0

Embed Size (px)

Citation preview

Scuola Politecnica e delle Scienze di Base Corso di Laurea in Ingegneria Informatica Elaborato finale in PROGRAMMAZIONE I

Programmazione di applicazioni Client-Server in un linguaggio interpretato: Python

Anno Accademico 2015/2016 Candidato: Mickael Di Carluccio matr. N46000541

Indice

Introduzione III

1 Python 1

1.1 Caratteristiche Fondamentali . . . . . . . . . . . . . . . . . . . . . . 2

1.2 Utilizzi tipici . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4

1.3 Primo approccio . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5

1.4 Costrutti di Controllo . . . . . . . . . . . . . . . . . . . . . . . . . . 7

1.5 Ciclo: For e While . . . . . . . . . . . . . . . . . . . . . . . . . . . 8

1.6 Strutture Dati . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10

1.7 File . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18

2 Programmazione Distribuita 21

2.1 Applicazioni Client-Server . . . . . . . . . . . . . . . . . . . . . . . 23

2.2 Architettura Client-Server . . . . . . . . . . . . . . . . . . . . . . . 25

2.3 Socket . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27

2.4 Tipi di Socket . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28

3 Programmazione in Python di un’applicazione Client-Server 30

3.1 Primo Esempio . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31

3.2 Trasferimento di File . . . . . . . . . . . . . . . . . . . . . . . . . . 33

Propongo di considerare questa

domanda:

"Le macchine sono in grado di

pensare?"

—Alan Turing

Introduzione

Python è un linguaggio di programmazione dinamico orientato agli oggetti utiliz-

zabile per molti tipi di sviluppo software. Offre un forte supporto all’integrazione

con altri linguaggi e programmi, è fornito di una estesa libreria standard e può

essere imparato in pochi giorni. Molti programmatori Python possono confermare

un sostanziale aumento di produttività e ritengono che il linguaggio incoraggi allo

sviluppo di codice di qualità e manutenibilità superiori. Python gira sui più comu-

ni sistemi operativi come Windows, Linux/Unix, Mac OS.

In questo elaborato si descrivono le caratteristiche fondamentali del linguaggio e

si illustrano i fondamenti della programmazione in Python di applicazioni client e

server comunicanti attraverso i protocolli TCP/IP.

Figura 1: Python

III

Capitolo 1

Python

Python è un linguaggio di programmazione ad alto livello, rilasciato pubblicamente

per la prima volta nel 1991 dal suo creatore Guido van Rossum, programmatore

olandese attualmente operativo in Dropbox. Deriva il suo nome dalla commedia

Monty Python’s Flying Circus dei celebri Monty Python, in onda sulla BBC nel

corso degli anni 70. Attualmente, lo sviluppo di Python (grazie e soprattutto

all’enorme e dinamica comunità internazionale di sviluppatori) viene gestito dal-

l’organizzazione no-profit Python Software Foundation. Python supporta diversi

paradigmi di programmazione, come quello object-oriented (con supporto all’ere-

ditarietà multipla), quello imperativo e quello funzionale, ed offre una tipizzazione

dinamica forte. È fornito di una libreria built-in estremamente ricca, che unita-

mente alla gestione automatica della memoria e a robusti costrutti per la gestione

delle eccezioni fa di Python uno dei linguaggi più ricchi e comodi da usare. Co-

modo, ma anche semplice da usare e imparare. Python, nelle intenzioni di Guido

van Rossum, è nato per essere un linguaggio immediatamente intuibile. La sua

sintassi è pulita e snella così come i suoi costrutti, decisamente chiari e non ambi-

gui. I blocchi logici vengono costruiti semplicemente allineando le righe allo stesso

modo, incrementando la leggibilità e l’uniformità del codice anche se vi lavorano

diversi autori. Python è un linguaggio pseudocompilato: un interprete si occupa

di analizzare il codice sorgente (semplici file testuali con estensione .py) e, se sin-

1

Capitolo 1. Python

tatticamente corretto, di eseguirlo. In Python, non esiste una fase di compilazione

separata (come avviene in C, per esempio) che generi un file eseguibile partendo

dal sorgente. L’esser pseudointerpretato rende Python un linguaggio portabile.

Una volta scritto un sorgente, esso può essere interpretato ed eseguito sulla gran

parte delle piattaforme attualmente utilizzate, siano esse di casa Apple (Mac) che

PC (Microsoft Windows e GNU/Linux). Semplicemente, basta la presenza della

versione corretta dell’interprete. Infine, Python è free software: non solo il do-

wnload dell’interprete per la propria piattaforma, così come l’uso di Python nelle

proprie applicazioni, è completamente gratuito; ma oltre a questo Python può es-

sere liberamente modificato e così ridistribuito, secondo le regole di una licenza

pienamente open-source. Queste caratteristiche hanno fatto di Python il protago-

nista di un enorme diffusione in tutto il mondo, e anche in Italia, negli ultimi anni.

Questo perché garantisce lo sviluppo rapido (e divertente) di applicazioni di qual-

siasi complessità in tutti i contesti: dal desktop al web, passando dallo sviluppo di

videogiochi e dallo scripting di sistema.

1.1 Caratteristiche Fondamentali

1. È free

Python è completamente gratuito ed è possibile usarlo e distribuirlo senza

restrizioni di copyright. Spesso alla parola “free” è associato il concetto di

“software non supportato”, ma questo non è assolutamente vero nel caso di

python: è sufficiente consultare periodicamente il sito ufficiale per rendersene

conto.

2. È orientato agli oggetti

Python è un linguaggio orientato agli oggetti, supporta nozioni avanzate di

polimorfismo, ereditarietà, operatori di overloading il tutto con una semplice

sintassi.

2

Capitolo 1. Python

3. È portabile

Python è un linguaggio portabile sviluppato in ANSI C. È possibile usarlo su

diverse piattaforme come: Unix, Linux, Windows, DOS, Macintosh, Sistemi

Real Time, OS/2, cellulari Nokia e Android, questo perché è interpretato,

quindi lo stesso codice può essere eseguito su qualsiasi piattaforma purché

abbia l’interprete Python installato.

4. È facile da usare

Chi ha fatto esperienza di programmazione con altri linguaggi non troverà

Python complesso da imparare. Si tratta infatti di un linguaggio di alto

livello con una sintassi dalle regole piuttosto semplici.

5. È ricco di librerie

La dotazione standard offre numerose librerie alle quali si aggiungono moduli

di terze parti che crescono continuamente. In Internet si trova materiale

relativo a HTML, PDF, XML, formati grafici, CGI e perfino interi Web

Server.

6. È performante

Python è un linguaggio interpretato. In questo caso “interpretato” non è

sinonimo di lento, infatti python “compila” il proprio codice in un byteco-

de molto efficiente. Questo permette di raggiungere prestazioni vicine ai

linguaggi in codice nativo. Inoltre python implementa molte strutture da-

ti e funzioni come componente intrinseca del linguaggio. Queste strutture

sono dette “built-in types and tools” e sono state sviluppate con accurata

efficienza.

7. Gestisce la memoria automaticamente

Come in Java, in Python esiste il meccanismo di “garbage collection“, che

permette di liberare il programmatore dall’ansia di allocazione selvaggia della

memoria.

3

Capitolo 1. Python

8. È integrabile ad altri linguaggi

Python può essere integrato ad altri linguaggi come .NET con IronPython o

python per .NET, Java con Jython

1.2 Utilizzi tipici

Python è un linguaggio come detto poc’anzi, molto potente ed infatti sono davvero

tanti gli ambiti in cui è usato:

1. Accesso ai Database:

Python definisce una modalità standard di accesso ai database, la cosiddetta

DB-API [1] attualmente alla v2.0. E’ possibile collegarsi con qualsiasi data-

base esistente, tra cui:

-Oracle

-MySQL

-SQLite

2. Applicazioni desktop:

Python include nella libreria standard i binding alla libreria di sviluppo TkIn-

ter [2], ma se desiderate interfacciarvi con altri toolkit grafici, non c’è che

l’imbarazzo della scelta. Tra le più diffuse segnaliamo:

-wxPython (fusione della libreria C++ wxWidgets con Python)

-PyQt (tutorial)

3. Giochi e grafica 3D:

Python è ampiamente usato per lo sviluppo di giochi sia a livello commerciale

che "hobbistico". Tra i principali strumenti ricordiamo:

-PyGame

-PyKyra

4

Capitolo 1. Python

4. Sviluppo software:

Esistono innumerevoli aspetti legati allo sviluppo software, che possono aiuta-

re ogni sviluppatore a diventare un programmatore migliore. Anche Python

non si sottrae a questo compito e fornisce alcuni strumenti a dir poco vitali:

-Trac è uno dei progetti migliori nel suo genere. Si tratta di un wiki che

integra un sistema di bugtracking altamente configurabile

-Buildbot è un framework studiato per costruire e controllare lo sviluppo

software attraverso test e definendo processi di sviluppo controllati

-Roundup è un semplice, ma efficace, sistema di tracciamento estremamente

personalizzabile.

1.3 Primo approccio

Scrivere codici in Python risulta davvero semplice e non ha bisogno di un compi-

ler. Si tratta di un linguaggio interpretato, e questo significa che il programma può

essere eseguito appena saranno finite le modifiche apportate al file. Questo rende

la revisione, la modifica e la risoluzione dei problemi di un programma molto più

rapida rispetto agli altri linguaggi. Come ogni programmatore sa, il primo approc-

cio a qualsiasi linguaggio di programmazione è la verifica dell’output a schermo del

messaggio "Hello, World!".

"Print" è una delle funzioni di base di Python, ed è usata per visualizzare infor-

mazioni nel terminale durante un programma. Al contrario di molti altri linguaggi

(es. C, C++), non serve indicare la fine di una linea con ";". Non servirà neppure

usare parentesi graffe () per indicare dei blocchi. Basterà indentare il testo per

indicare la sua inclusione in un blocco.

Una volta che le righe di codice sono finite, basterà salvare il file specificando l’e-

stensione del file ".py" . Assicurarsi di salvare il file in un punto di facile accesso,

perché si dovrà raggiungere il suo percorso dal prompt dei comandi.

5

Capitolo 1. Python

Come avviene l’esecuzione del programma?

Basterà aprire il Prompt dei Comandi o il Terminale e raggiungere il percorso dove

è stato salvato il file. Eseguire, poi, il file digitando "Nome_Programma".py. Nel

caso in esame, per un primo programma in Python, si è scelto di salvare il file con

la denominazione "hello.py".

—-Codice1 print(" Hello ,World!")

HelloWorld.py

—–Stampa1 Microsoft Windows [ Versione 6.1.7601] Copyright (c) 20092 Microsoft Corporation . Tutti i diritti riservati .3 C:\ Users\ Mickael Di Carluccio >D:\ Desktop \Tesi\hello.py4 Hello , World!

Come si può notare dalla Stampa, per poter avere accesso alla Directory in

cui risiede il file di interesse ".py" è necessario conoscere esattamente dove è stato

salvato il file e fare un’operazione di "change directory" con l’uso dello slash tra

una cartella e una sottocartella.

6

Capitolo 1. Python

1.4 Costrutti di Controllo

Si veda un esempio di programma con flusso di controllo dove c’è un input da

tastiera, e una verifica dell’età con i costrutti: if, elif, else ed una stampa sul

terminale del messaggio in base all’età inserita.

Codice

1 anni = int(input (" Inserisci la tua eta ’: "))2 if anni <= 12:3 print(" Che bello essere un bambino !")4 elif anni in range (13, 26):5 print(" Sei ancora un ragazzo !")6 else:7 print(" Chiamami Signore ")

—Stampa

1 Microsoft Windows [ Versione 6.1.7601] Copyright (c) 2009

2 Microsoft Corporation . Tutti i diritti riservati .

3 C:\ Users\ Mickael Di Carluccio >D:\ Desktop \Tesi\ Control .py

4 Inserisci la tua eta ’: 26

5 Sei ancora un ragazzo!

Vediamo meglio come viene interpretata la logica usata dai costrutti di controllo

if, elif, else.

-if : nell’esempio di cui sopra "se gli anni inseriti da tastiera sono un numero intero

inferiore o uguale a 12" potranno essere eseguite le istruzioni al suo interno.

N.B. Python non usa le parentesi graffe, bensì i due punti.

-elif : Abbreviazione di elseif è usata per indicare una seconda condizione da

controllare qualora la condizione specificata nel costrutto if non rispetti i parametri

specificati.

N.B. E’ stata usata anche la parola chiave range per indicare quali sono gli estremi

specificati.

else: è il costrutto che prende in esame i valori che non rientrano nelle condizioni

7

Capitolo 1. Python

dell’if e dell’elif.

Nel caso sopra citato qualora il valore di input inserito sia superiore a 26, verrà

mandata a video la stampa "Chiamami Signore".

1.5 Ciclo: For e While

In programmazione, ci sono molti programmi più elementari che usano la ricorsio-

ne per eseguire una ripetizione. Questa ripetizione è più comunemente chiamata

iterazione. Dato che l’iterazione è così comune, Python fornisce vari sistemi per

renderla più semplice da implementare. Il primo sistema è l’istruzione while.

Ecco un esempio, ContoAllaRovescia, viene riscritto usando l’istruzione while:

Codice

1 def ContoAllaRovescia (n):2 while n > 0:3 print n4 n = n-15 print (" Partenza !")

La chiamata ricorsiva è stata rimossa e quindi questa funzione ora non è più

ricorsiva.

Si può leggere il programma con l’istruzione while come fosse scritto in un linguag-

gio naturale:

"Finchè (while) n è più grande di 0 stampa il valore di n e poi diminuiscilo di 1.

Quando arrivi a 0 stampa la stringa "Partenza!"."

In modo più formale ecco il flusso di esecuzione di un’istruzione while:

1. Valuta la condizione controllando se essa è vera (1) o falsa (0).

2. Se la condizione è falsa esci dal ciclo while e continua l’esecuzione dalla prima

istruzione che lo segue.

3. Se la condizione è vera esegui tutte le istruzioni nel corpo del while e torna

al passo 1.

8

Capitolo 1. Python

Il corpo del ciclo while consiste di tutte le istruzioni che seguono l’intestazione e

che hanno la stessa indentazione. Questo tipo di flusso è chiamato ciclo o loop.

Nota che se la condizione è falsa al primo controllo, le istruzioni del corpo non sono

mai eseguite.

Il corpo del ciclo dovrebbe cambiare il valore di una o più variabili così che la

condizione possa prima o poi diventare falsa e far così terminare il ciclo. In caso

contrario il ciclo si ripeterebbe all’infinito, determinando un ciclo infinito. Nel

caso di ContoAllaRovescia possiamo essere certi che il ciclo è destinato a terminare

visto che n è finito ed il suo valore diventa via via più piccolo fino a diventare pari

a zero. Il ciclo for è un altro dei cicli di iterazione messi a disposizione dal linguag-

gio Python, si tratta in sostanza di un costrutto, comune anche ad altri linguaggi,

che consente di ripetere un’operazione un certo numero di volte, più tecnicamen-

te "iterare una sequenza o un oggetto", fino alla soddisfazione di una determinata

condizione (implicita) che terminerà il ciclo.

Per chiarire tale dinamica sarà possibile proporre un semplice esempio basato sul-

l’impiego delle liste, queste ultime sono un tipo di dato supportato da Python che

verrà analizzato nel prossimo paragrafo, per il momento basti sapere che una lista

permette di gestire un insieme di valori di diversa natura (stringhe, interi, decima-

li) delimitati da parentesi quadre e separati tramite una virgola.

Il codice proposto di seguito permetterà di ciclare e visualizzare in output tutti gli

elementi presenti in una lista definita dallo sviluppatore.

––FIBONACCI

1 # definizione della lista2 fibonacci = [1 ,1 ,2 ,3 ,5 ,8 ,13 ,21 ,34 ,55 ,89 ,144]3 # iterazione dei valori in lista4 for val in fibonacci :5 # stampa dei valori iterati6 print(val)

Nell’esempio mostrato la condizione da soddisfare per la terminazione del ciclo

sarà quindi quella di stampare fino all’ultimo valore presente nella lista passata

9

Capitolo 1. Python

come argomento, nel nostro caso "fibonacci".

Un fattore sintattico molto importante da tenere a mente riguarda il fatto che nella

digitazione di un ciclo for l’engine di Python si aspetta che l’istruzione associata

al ciclo venga indentata.

Vedremo nel paragrafo File anche l’istruzione break che è l’istruzione che per-

mette al ciclo di terminare anzitempo. Ossia, qualora si verificasse la condizione

desiderata, dopo le istruzione eseguite all’interno del ciclo While, break termina il

ciclo passando alla prima istruzione fuori dal ciclo.

1.6 Strutture Dati

Vediamo quali sono le strutture dati più usate come Liste, Pile, Code.

1.6.1 Liste

Una lista[4] è una serie ordinata di valori, ognuno identicato da un indice. I valori

che fanno parte della lista sono chiamati elementi. Le liste sono simili alle stringhe

essendo insiemi ordinati di caratteri, fatta eccezione per il fatto che gli elementi di

una lista possono essere di tipo qualsiasi. Liste e stringhe (e altri tipi di dati che si

comportano da insiemi ordinati) sono chiamate sequenze. Ci sono parecchi modi

di creare una lista nuova, e quello più semplice è racchiudere i suoi elementi tra

parentesi quadrate ([]):

1. [10, 20, 30, 40]

2. ["Pippo", "Pluto", "Paperino"]

Il primo esempio è una lista di quattro interi, il secondo una lista di tre stringhe.

Gli elementi di una stessa lista non devono necessariamente essere tutti dello stesso

tipo.

Questa lista, infatti, contiene una stringa, un numero in virgola mobile, un intero

10

Capitolo 1. Python

ed un’altra lista:

["ciao", 2.0, 5, [10, 20]]

Una lista all’interno di un’altra lista è detta lista annidata.

Le liste che contengono numeri interi consecutivi sono così comuni che Python

fornisce un modo semplice per crearle:

1 range (1 ,5)2 [1, 2, 3, 4]

La funzione range prende due argomenti e ritorna una lista che contiene tutti

gli interi a partire dal primo (incluso) fino al secondo (escluso). Ci sono altre due

forme per range. Con un solo argomento crea una lista a partire da 0:

1 range (10)2 [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

Se è presente un terzo argomento questo specifica l’intervallo tra valori successi-

vi, chiamato passo. Questo esempio mostra come ottenere una stringa dei numeri

dispari tra 1 e 10:

1 range (1, 10, 2)2 [1, 3, 5, 7, 9]

Infine esiste una lista speciale che non contiene alcun elemento: è chiamata lista

vuota ed è indicata da [ ].

1.6.2 Classi ed oggetti

Le classi sono tipi composti definiti dall’utente.

Vediamo nello specifico cosa significa e quali migliorie comporta. Creiamo dunque,

il tipo Punto.

Considerando il concetto matematico di punto nelle due dimensioni, il punto è

definito da una coppia di numeri (le coordinate). In notazione matematica le coor-

dinate dei punti sono spesso scritte tra parentesi con una virgola posta a separare

11

Capitolo 1. Python

i due valori. Per esempio (0, 0) rappresenta l’origine e (x, y) il punto che si trova

x unità a destra e y unità in alto rispetto all’origine. Un modo naturale di rappre-

sentare un punto in Python è una coppia di numeri in virgola mobile e la questione

che ci rimane da definire è in che modo raggruppare questa coppia di valori in un

oggetto composto: un sistema veloce anche se poco elegante sarebbe l’uso di una

tupla, anche se possiamo fare di meglio.

Un modo alternativo è quello di definire un nuovo tipo composto chiamato classe.

Una definizione di classe ha questa sintassi:

1 class Punto:2 pass

Le definizioni di classe possono essere poste in qualsiasi punto di un program-

ma ma solitamente per questioni di leggibilità sono poste all’inizio, subito sotto

le istruzioni import. Le regole di sintassi per la definizione di una classe sono le

stesse degli altri tipi composti: la definizione dell’esempio crea una nuova classe

chiamata Punto. L’istruzione pass non ha effetti: è stata usata per il solo fatto che

la definizione prevede un corpo che deve ancora essere scritto.

Creando la classe Punto abbiamo anche creato un nuovo tipo di dato chiamato con

lo stesso nome. I membri di questo tipo sono detti istanze del tipo o oggetti. La

creazione di una nuova istanza è detta istanziazione: solo al momento dell’istan-

ziazione parte della memoria è riservata per depositare il valore dell’oggetto. Per

creare un oggetto di tipo Punto viene chiamata una funzione chiamata Punto:

1 P1= Punto ()

Alla variabile P1 è assegnato il riferimento ad un nuovo oggetto Punto. Una

funzione come Punto, che crea nuovi oggetti e riserva quindi della memoria per

depositarne i valori, è detta costruttore. Possiamo aggiungere un nuovo dato ad

un’istanza usando la notazione punto:

12

Capitolo 1. Python

Figura 1.1: Assegnazione attributi alla classe Punto

1 P1.x = 3.02 P1.y = 4.0

In questo caso stiamo selezionando una voce da un’istanza e queste voci che

fanno parte dell’istanza sono dette attributi. Questo diagramma di stato mostra il

risultato delle assegnazioni:

La variabile P1 si riferisce ad un oggetto Punto che contiene due attributi

ed ogni attributo (una coordinata) si riferisce ad un numero in virgola mobile.

Possiamo leggere il valore di un attributo con la stessa sintassi:

1 print P1.y2 4.03 x = P1.x4 print x5 3.0

L’espressione P1.x significa "vai all’oggetto puntato da P1 e ottieni il valore del

suo attributo x". In questo caso assegniamo il valore ad una variabile chiamata

x: non c’è conflitto tra la variabile locale x e l’attributo x di P1: lo scopo della

notazione punto è proprio quello di identificare la variabile cui ci si riferisce evitando

le ambiguità.

13

Capitolo 1. Python

1.6.3 Pile

In questo paragrafo verrà esaminata la pila, un tipo di dato astratto molto comu-

ne. Una pila è una collezione e cioè una struttura di dati che contiene elementi

multipli.

Un TDA (Tipo Dato Astratto) è definito dalle operazioni che possono essere ef-

fettuate su di esso e che sono chiamate interfaccia. L’interfaccia per una pila

consiste di queste operazioni:

__init__: Inizializza un pila vuota.

Push: Aggiunge un elemento alla pila.

Pop: Rimuove e ritorna un elemento dalla pila. L’elemento tornato è sempre l’ul-

timo inserito.

EVuota: Controlla se la pila è vuota.

Una pila è spesso chiamata struttura di dati LIFO ("last in/first out", ultimo in-

serito, primo fuori) perché l’ultimo elemento inserito in ordine di tempo è il primo

ad essere rimosso: un esempio è una serie di piatti da cucina sovrapposti, ai quali

aggiungiamo ogni ulteriore piatto appoggiandolo sopra agli altri, ed è proprio dal-

l’alto che ne preleviamo uno quando ci serve.

Le operazioni che Python fornisce per le liste sono simili a quelle definite per la

nostra pila. Il codice utilizzato è chiamato implementazione del TDA Pila. Più in

generale un’implementazione è un insieme di metodi che soddisfano la sintassi e la

semantica dell’interfaccia richiesta.

—–Classe Pila1 class Pila:2 def __init__ (self ):3 self. Elementi = []4 def Push(self , Elemento ) :5 self. Elementi .append( Elemento )6 def Pop(self ):7 return self. Elementi .pop ()8 def EVuota(self ):9 return (self. Elementi == [])

14

Capitolo 1. Python

L’oggetto Pila contiene un attributo chiamato Elementi che è la lista di oggetti

contenuta nella pila.

Il metodo __init__ inizializza Elementi come lista vuota. Push inserisce un

nuovo elemento nella pila aggiungendolo a Elementi. Pop esegue l’operazione in-

versa, rimuovendo e ritornando l’ultimo elemento inserito nella pila. Per controllare

se la pila è vuota EVuota confronta Elementi con una lista vuota e ritorna vero/-

falso.

Un’implementazione di questo tipo in cui i metodi sono solo una semplice invoca-

zione di metodi già esistenti viene detta maschera.

1.6.4 Code

Questo paragrafo presenta due tipi di dati astratti (TDA): la Coda e la Coda con

priorità. Nella vita reale un esempio di coda può essere la linea di clienti in attesa

di un servizio di qualche tipo. Nella maggior parte dei casi il primo cliente della

fila è quello che sarà servito per primo, anche se ci possono essere delle eccezioni.

Ad esempio, all’aeroporto ai clienti il cui volo sta per partire può essere concesso

di passare davanti a tutti, indipendentemente dalla loro posizione nella fila o anche

al supermercato un cliente può scambiare per cortesia il suo posto con qualcuno

che deve pagare solo pochi prodotti.

La regola che determina chi sarà il prossimo ad essere servito si chiama politica

di accodamento. Quella più semplice è la FIFO ("First in, first out") dove il

primo che arriva è il primo ad essere servito. La politica di accodamento più

generale è l’accodamento con priorità dove a ciascun cliente è assegnata una priorità

ed il cliente con la massima priorità viene servito per primo indipendentemente

dall’ordine di arrivo.

Diciamo che questa politica di accodamento è la più generale perché la priorità

può essere basata su qualsiasi fattore: l’orario di partenza dell’aereo, la quantità

di prodotti da pagare ad una cassa o anche la gravità dello stato di un paziente al

15

Capitolo 1. Python

pronto soccorso.

I tipi di dati astratti Coda e Coda con priorità condividono lo stesso insieme di

operazioni. La differenza sta soltanto nella loro semantica: una Coda usa la politica

FIFO, mentre la Coda con priorità, come suggerisce il nome stesso, usa la politica

di accodamento con, appunto, priorità.

Una prima implementazione del TDA Coda a cui guarderemo è chiamata coda

linkata perché è composta di oggetti Nodo linkati. Ecco una definizione della

classe:

—–Classe Coda1 class Coda:2 def __init__ (self ):3 self. Lunghezza = 04 self.Testa = None5 def EVuota (self ):6 return (self. Lunghezza == 0)7 def Inserimento (self , Contenuto ):8 NodoAggiunto = Nodo( Contenuto )9 NodoAggiunto . ProssimoNodo = None

10 if self.Testa == None:11 # se la lista e’ vuota il nodo e’ il primo12 self.Testa = Nodo13 else:14 # trova l’ ultimo nodo della lista15 Ultimo = self.Testa16 while Ultimo . ProssimoNodo : Ultimo = Ultimo . ProssimoNodo17 # aggiunge il nuovo nodo18 Ultimo . ProssimoNodo = NodoAggiunto19 self. Lunghezza = self. Lunghezza + 120 def Rimozione (self ):21 Contenuto = self.Testa. Contenuto22 self.Testa = self.Testa. ProssimoNodo23 self. Lunghezza = self. Lunghezza - 124 return Contenuto

Il TDA Coda con priorità ha la stessa interfaccia del TDA Coda ma una se-

mantica diversa. L’interfaccia è sempre:

__init__ : Inizializza una nuova coda vuota. Inserimento: Aggiungi un elemento

alla coda. Rimozione: Rimuovi un elemento dalla coda. L’elemento da rimuovere

e ritornare è quello con la priorità più alta. EVuota: Controlla se la coda è vuota.

16

Capitolo 1. Python

La differenza di semantica è che l’elemento da rimuovere non è necessariamente il

primo inserito in coda, ma quello che ha la priorità più alta. Cosa siano le priorità

e come siano implementate sono fatti non specificati dall’implementazione, dato

che questo dipende dal genere di elementi che compongono la coda. Per esempio se

gli elementi nella coda sono delle stringhe potremmo estrarle in ordine alfabetico.

Se sono punteggi del bowling dal più alto al più basso, e viceversa nel caso del golf.

In ogni caso possiamo rimuovere l’elemento con la priorità più alta da una coda

soltanto se i suoi elementi sono confrontabili tra di loro.

Questa è un’implementazione di una coda con priorità che usa una lista Python

come attributo per contenere gli elementi della coda:

—–Classe Coda con priorità1 class CodaConPriorita :2 def __init__ (self ):3 self. Elementi = []4 def EVuota (self ):5 return self. Elementi == []6 def Inserimento (self , Elemento ):7 self. Elementi . append ( Elemento )8 def Rimozione (self ):9 Indice = 0

10 for i in range (1, len(self. Elementi )):11 if self. Elementi [i] > self. Elementi [ Indice ]:12 Indice = i13 Elemento = self. Elementi [ Indice ]14 self. Elementi [ Indice : Indice +1] = [ ]15 return Elemento

I metodi __init__ , EVuota e Inserimento sono tutte maschere delle opera-

zioni su liste. L’unico metodo "interessante" è Rimozione:

All’inizio di ogni iterazione Indice contiene l’indice dell’elemento con priorità mas-

sima. Ad ogni ciclo viene confrontato questo elemento con l’i-esimo elemento della

lista: se il nuovo elemento ha priorità maggiore, il valore di Indice diventa i.

Quando il ciclo for è stato completato Indice è l’indice dell’elemento con priorità

massima. Questo elemento è rimosso dalla lista e ritornato.

17

Capitolo 1. Python

1.7 File

Quando un programma è in esecuzione i suoi dati sono in memoria; nel momento

in cui il programma termina o il computer viene spento tutti i dati in memoria

vengono irrimediabilmente persi. Per conservare i dati devi quindi memorizzarli

in un file, solitamente memorizzato su hard disk, una memoria flash (pen drive o

schede di memoria) o CD-ROM.

Lavorando con un gran numero di file è logico cercare di organizzarli: questo viene

fatto inserendoli in cartelle (dette anche "folder" o "directory"). Ogni file all’interno

di una cartella è identificato da un nome unico.

Leggendo e scrivendo file i programmi possono scambiare informazioni e anche

generare documenti stampabili usando il formato PDF o altri formati simili.

Lavorare con i file è molto simile a leggere un libro: per usarli li devi prima aprire

e quando hai finito li chiudi. Mentre il libro è aperto lo puoi leggere o puoi scrivere

una nota sulle sue pagine, sapendo in ogni momento dove ti trovi al suo interno.

La maggior parte delle volte leggerai il libro in ordine, ma nulla ti vieta di saltare

a determinate pagine facendo uso dell’indice.

Questa metafora può essere applicata ai file. Per aprire un file devi specificarne il

nome e l’uso che intendi farne (lettura o scrittura).

L’apertura del file crea un oggetto file: nell’esempio che segue useremo la variabile

f per riferirci all’oggetto file appena creato.

1 f = open (" test.dat","w")2 print f3 <open file ’test.dat ’, mode ’w’ at fe820 >

La funzione open prende due argomenti: il primo è il nome del file ed il secondo

il suo "modo". Il modo "w" significa che stiamo aprendo il file in scrittura ("write").

Nel caso non dovesse esistere un file chiamato test.dat l’apertura in scrittura farà

in modo di crearlo vuoto. Nel caso dovesse già esistere, la vecchia copia verrà

rimpiazzata da quella nuova e definitivamente persa.

18

Capitolo 1. Python

Quando stampiamo l’oggetto file possiamo leggere il nome del file aperto, il modo

e la posizione dell’oggetto in memoria.

Per inserire dati nel file invochiamo il metodo write:

1 --- f.write (" Adesso ")2 --- f.write (" chiudi il file ")

La chiusura del file avvisa il sistema che abbiamo concluso la scrittura e rende

il file disponibile alla lettura:

1 --- f.close ()

Solo dopo aver chiuso il file possiamo riaprirlo in lettura e leggerne il contenuto.

Questa volta l’argomento di modo è "r":

1 --- f = open (" test.dat","r")

Se cerchiamo di aprire un file che non esiste otteniamo un errore:

1 --- f = open (" test.cat","r")2 IOError : [Errno 2] No such file or directory : ’test.cat ’

Il metodo read legge dati da un file. Senza argomenti legge l’intero contenuto

del file:

1 --- Testo = f.read ()2 --- print Testo3 Adesso chiudi il file

"read" accetta anche un argomento che specifica quanti caratteri leggere:

1 --- f = open (" test.dat","r")2 --- print f.read (5)3 Adess

Se non ci sono caratteri sufficienti nel file, read ritorna quelli effettivamentedisponibili. Quando abbiamo raggiunto la fine del file read ritorna una stringavuota:

19

Capitolo 1. Python

1 --- print f.read (1000006)2 o chiudi il file3 --- print f.read ()4 ---

La funzione che segue, copia un file leggendo e scrivendo fino a 50 caratteri per

volta. Il primo argomento è il nome del file originale, il secondo quello della copia:

1 def CopiaFile (Originale , Copia ):2 f1 = open(Originale , "r")3 f2 = open(Copia , "w")4 while 1:5 Testo = f1.read (50)6 if Testo == "":7 break8 f2.write(Testo)9 f1.close ()

10 f2.close ()11 return

L’istruzione break come già accennata nel paragrafo "Ciclo: For e While" in-

terrompe immediatamente il loop saltando alla prima istruzione che lo segue (in

questo caso f1.close()).

Il ciclo while dell’esempio è apparentemente infinito dato che la sua condizione

ha valore 1 ed è quindi sempre vera. L’unico modo per uscire da questo ciclo è

di eseguire un break che viene invocato quando Testo è una stringa vuota e cioè

quando abbiamo raggiunto la fine del file in lettura.

20

Capitolo 2

Programmazione Distribuita

Nell’ambito delle applicazioni informatiche si è soliti distinguere tra:

1. Architetture locali: tutti i componenti sono sulla stessa macchina.

2. Architetture distribuite: le applicazioni e i componenti possono risiedere su

nodi diversi messi in comunicazione da una rete.

I vantaggi della seconda alternativa consistono principalmente nella possibilità di

uso concorrente dei programmi, nella centralizzazione dei dati, nella distribuzione

del carico elaborativo, il tutto al prezzo di una maggiore complessità specialmente

riguardo alla comunicazione fra i vari compenenti.

Le applicazioni distribuite si possono classificare in base al «grado» di distribuzio-

ne:

1. Applicazioni client-server:

sono presenti solo due livelli e le operazioni sono svolte quasi interamente sul

servente. Come esempio possiamo citare i classici siti Web statici o dinamici;

gli strumenti per la realizzazione di tale tipo di applicazioni sono i socket di

rete, la cui programmazione è possibile in vari linguaggi, tra cui C, C++,

Java, Python.

21

Capitolo 2. Programmazione Distribuita

Figura 2.1: Modello Logico Client-Server

2. Applicazioni multi-livello:

si ha un numero maggiore di livelli, allo scopo, soprattutto, di alleggerire il

carico elaborativo dei serventi.

Quelle che vengono suddivise infatti sono le funzionalità del lato servente,

lasciando sostanzialmente invariate le caratteristiche della parte cliente che

ha il compito di ospitare l’interfaccia dell’applicazione.

Un esempio di tale tipo di architettura è quello del modello three-tier avente

una struttura suddivisa in tre strati o livelli:

(a) front-end o presentation tier o interfaccia;

(b) middle tier o logica applicativa;

(c) back-end o data tier o gestione dati persistenti.

Questa nomenclatura è tipica delle applicazioni Web; più in generale si può

fare riferimento ad una suddivisione in tre livelli, applicabile a qualsiasi

applicazione software, che è la seguente:

(a) PL (Presentation Layer):

è la parte di visualizzazione dei dati (moduli, «controlli» di input, ecc.)

necessari per l’interfaccia utente;

(b) BLL (Business Logic Layer):

è la parte principale dell’applicazione, che definisce le varie entità e le

loro relazioni indipendentemente dalle modalità di presentazione all’u-

tente e di salvataggio negli archivi;

22

Capitolo 2. Programmazione Distribuita

(c) DAL (Data Access Layer):

contiene tutto il necessario alla gestione dei dati persistenti (sostanzial-

mente sistemi di gestione di basi di dati).

Il numero di livelli può essere anche maggiore di tre, allo scopo di suddividere

ulteriormente i compiti dei vari strati; in questo caso si parla di applicazioni

multi-tier o n-tier.

2.1 Applicazioni Client-Server

Il termine "sistema client-server" (letteralmente cliente-serviente) indica un’archi-

tettura di rete nella quale genericamente un computer client o terminale client si

connette ad un server per la fruizione di un certo servizio, quale ad esempio la

condivisione di una certa risorsa hardware/software con altri client, appoggiandosi

alla sottostante architettura protocollare.

Più semplicemente, i sistemi client/server sono un’evoluzione dei sistemi basati

sulla condivisione semplice delle risorse: la presenza di un server permette ad un

certo numero di client di condividerne le risorse, lasciando che sia il server a gestire

gli accessi alle risorse per evitare conflitti di utilizzazione tipici dei primi sistemi

informatici.

2.1.1 Client

Il software client [3] in genere è di limitata complessità, limitandosi normalmente

ad operare come interfaccia verso il server. In generale nel campo informatico il

termine client indica una componente che accede ai servizi o alle risorse di un’altra

componente, detta server. In questo contesto si può quindi parlare di client rife-

rendosi all’hardware o al software.

Un computer collegato ad un server tramite rete locale o geografica, ed al quale

richiede uno o più servizi, utilizzando uno o più protocolli di rete è un esempio di

23

Capitolo 2. Programmazione Distribuita

client hardware.

Un programma di posta elettronica è un esempio di client software.

Sono sempre di più i software, come il web, l’e-mail, i database, che sono divisi

in una parte client (residente ed in esecuzione sul pc client) ed una parte server

(residente ed in esecuzione sul server). Il termine client indica anche il software

usato sul computer client per accedere alle funzionalità offerte dal server.

Ad esempio, nel web il software client è il web browser, e parla con un server web

attraverso il protocollo HTTP; per l’e-mail il client è detto in gergo mail user

agent o MUA (ad esempio, Outlook, Mozilla Thunderbird, Eudora, ...), e parla

con il server (Mail Transfer Agent o MTA) attraverso i protocolli SMTP e POP

o IMAP; il client per la consultazione o la modifica del database (spesso costituito

da librerie software utilizzate da un’applicazione) parla con il DBMS, che gestisce

il database e risponde alle interrogazioni del client.

2.1.2 Server

l software server, oltre alla gestione logica del sistema, deve implementare tutte le

tecniche di gestione degli accessi, allocazione e rilascio delle risorse, condivisione e

sicurezza dei dati o delle risorse.

Ad esempio un server di posta elettronica è paragonabile ad un qualunque ufficio

postale. Gli utilizzatori per accedere via client alla loro cassetta di posta elettro-

nica devono esser stati autorizzati. In modo analogo un utente deve possedere la

chiave della cassetta sita presso un ufficio postale dalla quale vuole prelevare la

corrispondenza.

2.1.3 Interazione Client-Server

Quando un computer client si connette direttamente ad un sistema di database o

ad una server application standard, questa viene chiamata 2-tier architecture (ar-

chitettura a 2 livelli).

24

Capitolo 2. Programmazione Distribuita

Recentemente, è più usuale per computer client, chiamati thin client che non in-

corporano business logic, ma solo elementi di interfaccia, connettersi ad una server

application che implementa una business logic nella quale transitivamente (ossia

successivamente) comunica con il database del server, il quale memorizza i dati

utilizzati dall’applicazione. Tale architettura è chiamata 3-tier architecture (archi-

tettura a 3 livelli).

In generale architetture ad n-livelli possono impiegare un certo numero di servi-

zi distinti, comprese relazioni transitive tra application server che implementano

differenti funzioni di business logic, ognuna delle quali può impiegare o meno un

sistema di database condiviso o distinto.

2.2 Architettura Client-Server

Vantaggi dell’architettura client-server

1. Il carico computazionale viene ripartito tra due piattaforme in genere distin-

te. Ognuna di esse può essere ottimizzata per i compiti a cui è destinata:

gestione di basi di dati, gestione di documenti, calcolo numerico, gestione di

strumentazione, interfaccia utente.

2. L’architettura si presta in modo naturale alla condivisione delle risorse: le

risorse gestite dal server sono accessibili in teoria da qualunque nodo di In-

ternet; se il server è realizzato in modo concorrente, l’accesso può avvenire

da più nodi simultaneamente.

3. Client e server possono:

(a) essere sviluppati su piattaforme (cioè sistemi operativi) diversi; tutti i

moderni sistemi operativi supportano infatti il protocollo TCP/IP;

25

Capitolo 2. Programmazione Distribuita

(b) essere sviluppati con linguaggi di programmazione diversi; tutti i mo-

derni linguaggi di programmazione supportano infatti il protocollo TC-

P/IP;

(c) essere sviluppati da programmatori diversi, creando così una modalità

naturale di ripartizione del lavoro in un team.

Svantaggi dell’architettura client-server

1. Maggior complessità del sistema.

2. Dipendenza da una connessione di rete efficace.

3. Procedura di sviluppo un po’ più complicata.

2.2.1 Architettura client-server TCP/IP

La connessione TCP/IP stabilisce un collegamento punto-punto tra due applica-

zioni. Gli estremi di questo collegamento sono contrassegnati da un indirizzo IP,

che identifica la workstation e da un numero di porta, che rende possibile la coe-

sistenza, sulla stessa workstation, di più connessioni, facenti capo ad applicazioni

indipendenti. Le applicazioni che utilizzano il protocollo TCP/IP in un contesto

client-server non solo devono conoscere ciascuna l’indirizzo IP e il numero di porta

dell’altra, ma devono anche condividere il protocollo dell’applicazione, che pertan-

to deve essere stato preventivamente definito.

Una volta stabilita la connessione e il protocollo cui scambiare dati su di essa, il

sottostante protocollo TCP/IP si incarica di far arrivare questi dati, suddivisi in

pacchetti, da un estremo all’altro del collegamento. In particolare, il protocollo

TCP si occupa di assemblare e disassemblare i pacchetti e di gestire l’handshaking

che garantisce l’affidabilità della connnessione, mentre il protocollo IP si occupa

del trasporto dei singoli pacchetti e della scelta del miglior instradamento degli

stessi lungo la rete. Questo meccanismo è alla base della robustezza del protocollo

26

Capitolo 2. Programmazione Distribuita

TCP/IP nel suo insieme, che a sua volta rappresenta una delle motivazioni dello

sviluppo del protocollo stesso in ambito militare (ARPAnet).

Le varie applicazioni standard esistenti (navigazione Web, trasferimento file, posta

elettronica e molte altre) utilizzano protocolli di applicazione standardizzati (http,

ftp, pop3, imap, smtp etc.). Ogni applicazione client-server specifica deve inve-

ce definire ed applicare il proprio protocollo di applicazione proprietario. Questo

può prevedere lo scambio di dati in blocchi di dimensioni fisse (è la soluzione più

semplice).

2.3 Socket

Un socket[5] è oggetto software che permette l’invio e la ricezione di dati, tra host

remoti (tramite una rete) o tra processi locali (Inter-Process Communication).

Data una qualsiasi piattaforma, è probabile che ci siano altre forme di IPC più

veloci, ma per la comunicazione tra piattaforme diverse i socket sono quasi una

scelta obbligata.

Furono inventati a Berkeley come parte dello Unix BSD. Si diffusero assai rapida-

mente con Internet. Per buone ragioni la combinazione dei socket con INET rende

la comunicazione con macchine di qualunque tipo sparse qua e là per il mondo in-

credibilmente facile (almeno se comparata con gli altri sistemi). Più precisamente,

il concetto di socket si basa sul modello Input/Output su file di Unix, quindi sulle

operazioni di open, read, write e close; l’utilizzo, infatti, avviene secondo le

stesse modalità, aggiungendo i parametri utili alla comunicazione, quali indirizzi,

numeri di porta e protocolli.

Socket locali e remoti in comunicazione, formano una coppia (pair), composta da

indirizzo e porta di client e server.

Solitamente i sistemi operativi forniscono delle API per permettere alle applica-

zioni di controllare e utilizzare i socket di rete.

27

Capitolo 2. Programmazione Distribuita

I tipi di protocolli utilizzati dal socket, ne definiscono la famiglia (o dominio).

Possiamo distinguere, ad esempio, due importanti famiglie:

1. AF_INET : comunicazione tra host remoti, tramite Internet;

2. AF_UNIX : comunicazione tra processi locali, su macchine Unix. (Questa

famiglia è anche chiamata Unix Domain Socket).

2.4 Tipi di Socket

All’interno della famiglia possiamo distinguere il tipo di socket, a seconda della

modalità di connessione. Abbiamo:

1. Stream socket: orientati alla connessione (connection-oriented), basati su

protocolli affidabili come TCP o SCTP;

2. Datagram socket: non orientati alla connessione (connectionless), basati

sul protocollo veloce ma inaffidabile UDP;

3. Raw socket (raw IP): il livello di trasporto viene bypassato, e l’header è

accessibile al livello applicativo.

2.4.1 Stream Socket

Vedremo più nel particolare solo questa tipologia di Socket.

Essendo basati su protocolli a livello di trasporto come TCP, garantiscono una

comunicazione affidabile, full-duplex, orientata alla connessione, e con un flusso di

byte di lunghezza variabile.

La comunicazione mediante questo socket, si compone di queste fasi:

1. – Creazione dei socket

Client e server creano i loro rispettivi socket, e il server lo pone in ascolto su

una porta.

28

Capitolo 2. Programmazione Distribuita

Dato che il server può creare più connessioni con client diversi (ma anche con

lo stesso), ha bisogno di una coda per gestire le varie richieste.

2. – Richiesta di connessione

Il client effettua una richiesta di connessione verso il server. Da notare che

possiamo avere due numeri di porta diversi, perchè una potrebbe essere de-

dicata solo al traffico in uscita, l’altra solo in entrata; questo dipende dalla

configurazione dell’host. In sostanza, non è detto che la porta locale del client

coincida con quella remota del server.

Il server riceve la richiesta e, nel caso in cui sia accettata, viene creata una

nuova connessione.

3. – Comunicazione

Ora client e server comunicano attraverso un canale virtuale, tra il socket del

primo, ed uno nuovo del server, creato appositamente per il flusso dei dati di

questa connessione: data socket. In fede di quanto accennato nella prima

fase, il server crea il data socket perchè il primo serve esclusivamente alla

gestione delle richieste.

È possibile, quindi, che ci siano molti client a comunicare con il server,

ciascuno verso il data socket creato dal server appositamente per loro.

4. – Chiusura della connessione

Essendo il TCP un protocollo orientato alla connessione, quando non si ha più

la necessità di comunicare, il client lo comunica al server, che ne deistanzia

il data socket. La connessione viene così chiusa.

29

Capitolo 3

Programmazione in Python di

un’applicazione Client-Server

Questo capitolo tratterà in modo dettagliato le applicazioni client-server in Py-

thon, linguaggio di programmazione analizzato nel capitolo 1.

Utilizzeremo un protocollo di comunicazione TCP/IP tra Client e Server.

Vedremo prima un’applicazione che tratterà la comunicazione semplice tra un client

ed un server con uno scambio di messaggi e successivamente, in maniera più det-

tagliata l’invio di un file da parte del server, scelto dal client.

30

Capitolo 3. Programmazione in Python di un’applicazione Client-Server

3.1 Primo Esempio

Vediamo un primo esempio in cui il server si mette in ascolta su una porta prede-

finita ed in seguito ad una connessione TCP/IP con il client, lo stesso client invia

la data e l’ora relativa alla connessione effettuata.

Server.py1 # server .py2 import socket3 import time4 # create a socket object5 serversocket = socket . socket (6 socket .AF_INET , socket . SOCK_STREAM )7 # get local machine name8 host = socket . gethostname ()9 port = 9999

10 # bind to the port11 serversocket .bind ((host , port ))12 # queue up to 5 requests13 serversocket . listen (5)14 while 1:15 # establish a connection16 clientsocket ,addr = serversocket . accept ()17 print (" Connessione con [addr ],[ port] %s" % str(addr ))18 currentTime = time.ctime(time.time ()) + "\r\n"19 clientsocket .send( currentTime . encode (’ascii ’))20 clientsocket .close ()

1. socket.socket(): Crea un nuovo socket utilizzando il dato indirizzo, il tipo

di socket ed il numero di protocollo.

2. socket.bind(address): Associa il socket all’indirizzo.

3. socket.listen(backlog): Ascolta le connessioni fatte al socket. L’ar-

gomento("backlog") specifica il numero massimo di connessioni in coda che

saranno almeno 0; il massimo valore dipende dal sistema (di solito è 5), il

minimo valore è sempre 0.

4. socket.accept(): Il valore di ritorno è una coppia (conn, address) dove

conn è un nuovo oggetto socket che serve a mandare e ricevere dati, e ad-

dress è l’indirizzo legato al socket.

31

Capitolo 3. Programmazione in Python di un’applicazione Client-Server

Una volta accettato, un nuovo socket viene creato ed avrà un proprio indenti-

ficativo. Questo nuovo socket è utilizzato unicamente con questo particolare

client.

5. socket.send(bytes[, flags]): Invia dati al socket. Il socket deve essere

connesso al socket. Ritorna il numero di bytes inviati.

6. socket.close(): Indica la chiusura del socket. Tutte le operazioni successi-

ve sul socket falliranno.I socket sono automaticamente chiusi quando vengono

rifiutati, ma è sempre raccomandato chiuderli con l’operazione close().

Client.py1 # client .py2 import socket3 # create a socket object4 s = socket . socket ( socket .AF_INET , socket . SOCK_STREAM )5 # get local machine name6 host = socket . gethostname ()7 port = 99998 # connection to hostname on the port.9 s. connect ((host , port ))

10 # Receive no more than 1024 bytes11 tm = s.recv (1024)12 s.close ()13 print (" Time connection server : %s" % tm. decode (’ascii ’))

Output1 $ python server .py &2 Connessione con [addr ],[ port] ( ’127.0.0.1 ’ , 54597)3

4 $ python client .py5 Time connection server is Wed Apr 20 16:32:15 2016

32

Capitolo 3. Programmazione in Python di un’applicazione Client-Server

3.2 Trasferimento di File

Si veda un esempio di applicazione Client-Server con l’utilizzo dei file[6].

—Server.py1 # server .py2

3 import socket4 port = 600005 s = socket . socket ()6 host = socket . gethostname ()7 s.bind ((host , port ))8 s. listen (15)9 print (’ Server listening .... ’)

10 while True:11 conn , addr = s. accept ()12 print (’Got connection from ’, addr)13 data = conn.recv (1024)14 print(’ Server received ’, repr(data. decode ()))15 filename =’ mytext .txt ’16 f = open(filename ,’rb ’)17 l = f.read (1024)18 while (l):19 conn.send(l)20 print(’Sent ’,repr(l. decode ()))21 l = f.read (1024)22 f.close ()23 print(’Done sending ’)24 conn.send(’->Thank you for connecting ’. encode ())25 conn.close ()

—Output Server1 Microsoft Windows [ Versione 6.1.7601]2 Copyright (c) 2009 Microsoft Corporation .3 Tutti i diritti riservati .4

5 C:\ Users\ Mickael Di Carluccio >"C:\ server .py"6 Server listening ....7 Got connection from ( ’192.168.1.11 ’ , 62793)8 Server received ’Hello Server !’9 Sent ’ciao a tutti ’

10 Done sending

33

Capitolo 3. Programmazione in Python di un’applicazione Client-Server

–-Client.py

1 # client .py2

3 import socket4 s = socket . socket ()5 host = socket . gethostname ()6 port = 600007 s. connect ((host , port ))8 s.send(’Hello Server !’. encode ())9 with open(’ received .txt ’, ’wb ’) as f:

10 print (’file opened ’)11 while True:12 print(’ receiving data ... ’)13 data = s.recv (1024)14 if not data:15 break16 print(’Data => ’, data. decode ())17 # write data to a file18 f.write(data)19 f.close ()20 print(’ Successfully get the file ’)21 s.close ()22 print(’ connection closed ’)

—Output Client1 Microsoft Windows [ Versione 6.1.7601]2 Copyright (c) 2009 Microsoft Corporation .3 Tutti i diritti riservati .4

5 C:\ Users\ Mickael Di Carluccio >"C:\ client .py"6 file opened7 receiving data ...8 Data => ciao a tutti9 receiving data ...

10 Data => ->Thank you for connecting11 receiving data ...12 Successfully get the file13 connection closed14

15 C:\ Users\ Mickael Di Carluccio >

34

Conclusioni

In questo elaborato abbiamo esaminato il modo con cui è possibile programmare

un’applicazione Client/Server in linguaggio Python.

L’obiettivo prefissato prevedeva la programmazione in linguaggio Python, di un’ap-

plicazione Client/Server in grado di aprire un file, copiare il contenuto al suo interno

e di scriverlo in un nuovo file, salvandolo.

Dapprima, però, abbiamo discusso delle potenzialità che questo linguaggio inter-

pretato ci fornisce, descrivendo i suoi vantaggi e svantaggi, di come vengono di-

chiarate le strutture dati e di come, proprio per il conseguimento dell’obiettivo, di

come vengono trattati i file.

Essendo un’applicazione Client/Server, abbiamo discusso anche di quelle che sono

le applicazioni distribuite, descrivendone struttura e architettura. Ma non solo.

Abbiamo discusso di come è stato possibile, far comunicare un applicativo Client,

con un Server, secondo i vari protocolli di rete, come il TCP/IP e l’UDP.

La tesi tratta argomenti davvero interessanti soprattutto per chi, come me, si è

affacciato per la prima volta al mondo Python, restandone davvero sorpreso e me-

ravigliato. Tra i numerosi vantaggi, quelli che più mi hanno colpito sono: non

prevedono parenti graffe, ma si basa solo sulla corretta indentazione delle righe di

codice, ma anche e soprattutto dal fatto che non esiste un vero e proprio compila-

tore del Python, infatti, con un semplice editor di testo è possibile scrivere righe

di codice per poi verificarle con un Prompt dei comandi.

Quest’ultima valutazione, considerata da me un vantaggio, fa sì che in qualunque

35

Capitolo 3. Programmazione in Python di un’applicazione Client-Server

momento ed in qualunque luogo, in presenza di un pc, è possibile "buttare giù"

righe di codice. Tra le società più importanti che usano Python abbiamo:

1. Google (molti componenti del motore di ricerca)

2. Industrial Light+Magic (Star Wars Episode II...)

3. Infoseek (search engine)

4. Yahoo! Groups (mailing list manager)

5. Nasa (vari utilizzi, tra cui strumenti per il pre-mission planning dello Space

Shuttle)

6. IBM (test automatici di strumenti internet)

7. Blender 3D (scripting language).

Ciò fa capire la potenza di Python che viene scelto da numerose aziende a discapito

di tanti altri linguaggi di programmazione.

36

Ringraziamenti

Ringrazio per aver reso possibile il conseguimento della mia laurea, innanzitutto i

miei genitori, che mi hanno sempre incitato ed esortato a non mollare quando le

cose non andavano per il verso giusto.

Ringrazio poi, i miei colleghi, Filippo Masi e Francesco Apuzzo per aver condiviso

insieme il percorso di studi che ci ha accompagnati fino al termine degli esami, rin-

grazio Francesco soprattutto per il tempo dedicatomi, nonostante ne avesse poco

lui stesso.

Ringrazio i miei compagni di vita, Davide D’Ambrosio, Andrea Esposito, Ernesto

Borruto e tutti gli amici della palestra che hanno seguito il mio cammino verso la

laurea.

37

Bibliografia

[1] http://www.python.it/doc/articoli/PyDbAPI2_0.html

[2] http://linuxdidattica.org/docs/altre_scuole/msm_p/txs_01.html#id6

[3] https://it.wikipedia.org/wiki/Sistema_client/server

[4] "Pensare da informatico - Imparare con Python" Allen Downey, Jeffrey Elkner,

Chris Meyers

[5] http://fortyzone.it/socket-cosa-sono/

[6] http://www.bogotobogo.com/python/python_network_programming_server_client.php

38