Modulo B - Dipartimento di Fisica

Transcript

Modulo B - Dipartimento di Fisica
Universita' degli Studi di Roma - La Sapienza
Corso di laurea in Fisica
DISPENSE DEL CORSO DI CALCOLATORI ELETTRONICI (Modulo B)
========================================================
Tenuto dal Prof. Roberto Biancastelli
N.B. Per ridurre le dimensioni del file tutta la grafica e' stata
realizzata in modalita? testo, usando i caratteri grafici che
devono essere disponibili nel programma di visualizzazione.
Si puo' usare il programma NotePad, con caratteri Terminal.
Anno Accademico 2003-2004
Copyright 1988-2004
!-----------------------------------------------------------------------
PREFAZIONE
══════════
Il corso e quindi anche le dispense sono suddivisi in tre 'moduli' A, B e
C, organizzati come indicato nel programma. I primi due sono per la laurea
quadriennale, mentre il modulo C (capitoli 6-14) e' per la laurea triennale
(richiede la propedeuticita' dei corsi di Laboratorio di Calcolo e di
Comunicazione Scientifica e Tecnologica).
La relativa didattica e' stata organizzata in una serie di dispense in
vista di un'informatizzazione completa del corso, con tecnologie multimediali e telematiche.
Queste dispense, con tutti i programmi delle esercitazioni pratiche, sono
distribuite gratuitamente su floppy disk in copia unica e per uso personale
esclusivo, ai soli studenti regolarmente iscritti al corso del prof.Roberto
Biancastelli.
Contenendo dei caratteri grafici, le dispense sono visualizzabili e stampabili con i programmi editor standard (in MS-DOS con EDIT o in Windows con
NotePad, caratteri 'Terminal' e Formato senza "A capo automatico").
Se la dimensione di un file risultasse 'troppo estesa', occorre modificare
le impostazioni di memoria della finestra DOS, cliccando prima con il pulsante destro sull'icona DOS o sulla barra del titolo della finestra DOS e
poi con il pulsante sinistro su Proprieta' ed impostando quindi tutte le
opzioni in 'Automatico').
I files scritti in formato Word invece possono essere letti dagli studenti,
che non possiedono il programma MS-Word, scaricando gratuitamente dal sito
della Microsoft ( www.microsoft.com --> Office --> Word Downloads ) il
programma WordViewer97/2000 (wd97vwr32.exe).
E' opportuno precisare che, essendo il resto del corso di laurea in fisica
piuttosto povero di insegnamenti informatici, il compito che attende lo
studente del corso di Calcolatori Elettronici e' piuttosto impegnativo.
Cio' perche' questa materia, a differenza di altre, e' soggetta ad un
continuo e rapido progresso tecnologico, che ha ampliato sempre di piu'
negli ultimi anni il campo di insegnamento.
Poiche' molti studenti arrivano a questo corso con una conoscenza iniziale
della materia praticamente nulla, il docente deve risolvere due problemi
di non poco conto: insegnare sempre di piu' nello stesso numero di lezioni
e gestire didatticamente la crescente complessita' delle nuove tecnologie
informatiche. La soluzione finora adottata e' stata quella di inserire
gradualmente nel programma una parte su tecnologie avanzate e programmazione
ad oggetti ed in rete.
Gli studenti che, non avendo avuto una conoscenza iniziale della materia,
si trovassero in difficolta' nella preparazione all'esame su quest'ultima
parte non dovranno preoccuparsi, perche' nell'esame finale non verra' loro
richiesta in modo fiscale una conoscenza approfondita di questi argomenti.
Si tenga inoltre presente che in questo corso l'apprendimento non deve
essere finalizzato al voto, ma all'acquisizione di una professionalita'in
questa materia, che sia spendibile poi nel mondo del lavoro e della ricerca).
Tuttavia gli studenti arrivati a questo corso senza precedenti conoscenze
propedeutiche all'informatica di base (algebra di Boole, elettronica
digitale,
ecc.) sono invitati a studiare dall'inizio tutti gli argomenti esposti nel
programma e spiegati nelle lezioni, tralasciando eventualmente gli ultimi
argomenti riguardanti la programmazione in rete, applet java, ecc.
Invece gli studenti arrivati a questo corso, con le conoscenze di base ed
una certa esperienza di programmazione in un qualche linguaggio di alto
livello precedentemente acquisita, potranno rinfrescare velocemente le
loro conoscenze di base, esposte nella prima parte del programma e nelle
lezioni, dedicando poi un tempo maggiore sulle ultime parti del programma
riguardanti la programmazione ad oggetti, in rete, Internet, ecc.
La modalita' di svolgimento delle esercitazioni e' stata organizzata in
modo da permettere anche il lavoro parallelo di gruppi di studenti, che
trattano argomenti diversificati in funzione della loro preparazione e
degli obiettivi proposti (nell'ambito degli argomenti trattati nel corso).
Ove possibile, con le cautele sotto indicate per impedire la diffusione di
virus informatici, la prosecuzione del lavoro pratico sul computer di casa
e' vivamente incoraggiata.
!----------------------------------------------------------------------INDICE GENERALE
═══════════════
INDICE
PROGRAMMA DEL CORSO DI CALCOLATORI ELETTRONICI
PROGRAMMA LOGICO DEL CORSO
INTRODUZIONE
Capitolo
1 - Elementi del linguaggio Pascal
Capitolo
2 - Sistemi di numerazione e rappresentazione delle informazioni
Capitolo
3 - Strutture di dati
Capitolo
4 - Introduzione all'algebre di Boole
Capitolo
5 - Circuiti logici digitali
Capitolo
Capitolo
Capitolo
Capitolo
Capitolo
Capitolo
Capitolo
Capitolo
Capitolo
Modulo C
6 - Architettura di un calcolatore elettronico <──────────┐
│
7 - Sottoprogrammi e passaggio dei parametri
│
│
│
8 - Programmazione Assembly
│
Fine Modulo A
│
9 - Sistema di Input/Output
<───────────────>
│
Inizio Modulo B
│
10 - Programmazione concorrente
│
│
11 - Sistema di memoria
│
│
12 - Sistemi operativi
│
│
13 - Sistemi in rete
│
│
14 - Programmazione ad oggetti e linguaggio Java <─────────┘
Capitolo 15 - Programmazione sul Web: Apache, HTML, CGI, Java apple
Capitolo 16 - Architetture avanzate
Capitolo 17 - Acquisizione di dati sperimentali
APPENDICE A - Sigle e definizioni utili
APPENDICE B - Il simulatore H6809
APPENDICE C - Programma delle esercitazioni
!----------------------------------------------------------------------Programma del Corso di CALCOLATORI ELETTRONICI
══════════════════════════════════════════════
Prof.R.Biancastelli - Dipartimento di Fisica
Universita' di Roma - La Sapienza
────────── MODULO A ───────────
RAPPRESENTAZIONE DELLE INFORMAZIONI (D,W): Sistemi numerici - Rappresentazioni posizionali - Conversioni di base - Rappresentazioni dei negativi
Aritmetica binaria in complemento a due -Carry e Overflow - Rappresentazione dei numeri frazionari - Conversioni in virgola fissa e virgola mobile - Rappresentazione BCD - Codici binari.
ELEMENTI DI PASCAL (W,D,G): Intestazioni, tipi e dichiarazioni di variabili, istruzioni semplici e composte, diagrammi sintattici - Procedure
e funzioni - Parametri formali e passaggio dei parametri.
STRUTTURE DI DATI (D,W): Vettori e matrici - Pile (Stack) - Code - Liste
(a singolo e doppio 'link') - Gestione delle liste: free list e garbage
collection.
INTRODUZIONE ALL'ALGEBRA DI BOOLE (C,D): Operazioni e loro proprieta' Teorema di De Morgan e legge di dualita' - Teorema di sviluppo: Mintermini, Maxtermini e forma canonica - Minimizzazione: il metodo delle
mappe di Karnaugh - Operatori universali - Operatore OR-esclusivo
(coincidenza e anticoincidenza).
│
CIRCUITI LOGICI DIGITALI (C,D): Circuiti combinatori SSI: Analisi
e sintesi - Circuiti combinatori MSI, LSI - Sintesi a ROM e PLA Circuiti sequenziali - Memorie ROM, RAM statiche, dinamiche e
associative.
Modulo C
<────────┐
ARCHITETTURA DI UN ELABORATORE (D,W): Organizzazione interna - Bus
│
di memoria - Registri - Contatori di programma e unita' di controllo
│
Unita' aritmetica - I/O bus - Istruzioni - Modi di indirizzamento: a
│
registro , a registro indiretto , assoluto , assoluto indiretto, imme│
diato, autoincremento, relativo, a registro base e indexato - Sistema
│
di I/O: sistemi a bus dedicato e memory mapped - Porte di I/O - Proto│
colli Handshake - Interruzioni - Microcomputer H6809 e sua simulazione
│
in Pascal.
│
│
PROGRAMMAZIONE ASSEMBLY (D,W) - Pseudo-istruzioni - Compilazione: PLC,
│
tabella dei simboli e modulo oggetto - Correlatore (Link Editor) │
Caricatore (Loader) - Rilocazione - Macro-istruzioni.
│
│
─────────── MODULO B ───────────
│
│
ELABORATORI NUMERICI (D,W): Organizzazione interna dell'unita' centrale │
Microcomputer H6809 e sua simulazione in Pascal - Unita' di controllo
│
canalizzate - Gestione della memoria - Memory Management Unit │
Paginazione (memory mapping): mappa di traduzione degli indirizzi │
Classificazione delle macchine: ad accumulatori (H6809), a registri
│
generali (H8000) ed a stack (H11) - Processori RISC.
│
│
SISTEMA DI INPUT/OUTPUT (W,D): Sistemi a bus dedicato e memory mapped
│
- Porte di I/O - Protocolli Handshake - Interfacciamenti: Paralleli
│
(Centronix, IEEE 488) e seriali (asincrono RS232C e sincroni BSC) │
Programmazione I/O e sovrapposizione - I/O drivers - Sistema di inter│
ruzione - Gestione delle priorita': geografica, daisy chain, mask bits,
│
round-robin, polling e interruzioni vettorizzate - Interruzioni interne
│
(traps) e software (system calls) - Programmazione delle interruzioni │
Accesso diretto alla memoria (DMA) - Sottosistemi a dischi - Canali di
│
I/O controllati da processori.
│
│
PROGRAMMAZIONE CONCORRENTE (D,W): Processi e loro stati - Concorrenza
│
con I/O in sovrapposizione - Variabili condivise e sezioni critiche │
Errori timing-dependent e stallo (dead-lock) - Protezione delle sezioni
│
critiche - Semafori - Bloccaggio di strutture di dati - Condivisione di
│
struzioni.
│
│
SISTEMA DI MEMORIA (D,P): Organizzazione gerarchica - Memoria a banchi,
│
interleaved, multiport - Fetch multiplo - Registro di istruzioni a
│
buffer - Memoria cache - Memoria virtuale - Gestione della memoria:
│
partizioni fisse e variabili, paginazione, memoria virtuale.
│
│
SISTEMI OPERATIVI E RETI (C,D,I): Dedicati, a lotti (batch) e interattivi
│
(time-sharing) - Multitasking e multiprogrammazione - Reti locali │
Software di rete
│
│
ELEMENTI DEL LINGUAGGIO JAVA (D,J): Programmazione ad oggetti - Fondamenti │
del linguaggio Java: classi, oggetti, variabili e metodi - I/O in Java │
Interfaccia grafica Swing (GUI) - Gestione degli eventi e delle eccezioni - │
Applicazioni e applet - Connessioni in rete e programmazione client-server. │
<─────────┘
INTERCONNESSIONE DI RETI E INTERNET (D,I,H) - Indirizzamento IP - Protocolli
TCP - Inter-reti - Internet - Browser e linguaggio HTML - Web server Script CGI e Javascript
ARCHITETTURE AVANZATE (C,D): Classificazione dei sistemi di elaborazione parallela: MISD, SIMD,MIMD - Tipi di accoppiamento: Multiproces-
sor, multicomputer e reti locali - Esempi
ACQUISIZIONE DI DATI SPERIMENTALI (D): Sistemi standard di acquisizione di dati (NIM, CAMAC, VME e FASTBUS) - Organizzazione di un sistema
multitask in tempo reale - Supervisione dell'elaborazione parallela
(centralizzata e distribuita) - Multiprocessing (esempi su VME e FASTBUS).
─────────── ESERCITAZIONI ───────────
Modulo A: Programmazione in Pascal - Simulatore del computer H6809 Uso pratico del linguaggio binario e mnemonico Assembly del
computer H6809 con simulatore e debugger.
Modulo B: Programmazione concorrente su rete locale di PC (farm per la
simulazione Montecarlo dello scattering coulombiano) - Uso
pratico del linguaggio Java - Istallazione ed uso di Web server
con uso di applet Java, Javascript e script CGI - Programmazione
concorrente (client-server) su rete Intranet.
Modulo C: Uso pratico del linguaggio binario e mnemonico Assembly del
computer H6809 con simulatore e debugger - Programmazione
concorrente su rete locale di PC (farm per la simulazione
Montecarlo dello scattering coulombiano) - Uso pratico del
linguaggio Java - Programmazione concorrente (client-server)
su rete Intranet.
PRINCIPALI RIFERIMENTI BIBLIOGRAFICI:
────────────────────────────────────
Testo base:
D: Dispense, esercizi e fotocopie di appunti/trasparenze distribuite
gratuitamente dal docente su floppy disk.
Testi per consultazione:
W: J.Wakerly - Microcomputer Architecture and Programming - Ed. Wiley
G: M.Gori et al. - Pascal e C - Ed. Mc Graw Hill
C: G.Cioffi,V.Falzone - Manuale di Informatica - Ed. Calderini
P: D.A.Patterson et al.- Struttura e progetto...- I/F Hard/Softw.
J: Cay Horstmann - JAVA 2, i fondamenti - Ed. Mc Graw Hill
I: D.Comer - Internet e reti di calcolatori - Ed. Addison-Wesley
H: G.B.Shelly et al. - HTML imparare per progetti
Per informazioni, spiegazioni e chiarimenti e' possibile concordare durante
tutto l'anno accademico incontri con il professore al
349.5553010
anche al di fuori degli orari di ricevimento (studenti lavoratori).
Si puo' comunicare con il professore anche all'indirizzo di posta elettronica
[email protected]
!----------------------------------------------------------------------PROGRAMMA LOGICO DEL CORSO
==========================
(Grafo che evidenzia le connessioni logiche tra i vari argomenti)
RAPPRESENTAZIONE
INFORMAZIONI
──────┬──────
│
┴
STRUTTURE DATI
───────┬──────
│
┴
ALGEBRA DI BOOLE
────────┬───────
│
┴
ELETTRONICA DIGITALE
──────────┬─────────
│
┴
ARCHITETTURA ELABORATORE
^
┌──────────────────────────┐
│
│
UNITA' CENTRALE
│
│
│
┬
│
┴
┌───│─< SISTEMA │ SISTEMA >──│───┐
Modulo A
│
│
I/O
│ MEMORIA
│
│
│
└────────────┼─────────────┘
│
.........
│
│
│
│
PROGRAMMAZIONE
│
Modulo B
│
(ASSEMBLY,PASCAL,JAVA...)
│
┬
│
│
│
│
│
│
│
│
SISTEMA ────> PROGRAMMAZIONE
MEMORY
│
D'INTERRUZIONE
CONCORRENTE
MANAGEMENT
│
│
│
│
│
│
│
│
v
│
┌─────────┴────────┐
│
└─────>│ SISTEMI OPERATIVI│<───────┘
│
MONOUTENTE
│
└─────────┬────────┘
│
│
SPECIALI ACCORGIMENTI
HARDWARE
│
│
┌───────────┴───────────┐
│
SISTEMI OPERATIVI
│
┌───────────────│ MULTIUTENTE,MULTITASK │────────────┐
│
│
SOFTWARE DI RETE
│
│
│
└───────────┬───────────┘
│
│
│
│
│
│
│
│
MULTIPROGRAMMAZIONE <──┼──> MULTIPROCESSING
│
│
─┬
│
┬─
│
│
│
│
│
│
────┴────────────────
│
│
│
──────────────┴──────────────
ARCHITETTURE AVANZATE
│
│
│
RETI LOCALI/INTERNET/INTRANET
│
─┬──
│
│
│
─┬─
│
│
│
│
│
│
│
┌─┴─────┴───────┴──────┴─────────┴──┐─────> CAMAC
│
│ ACQUISIZIONE DI DATI SPERIMENTALI │─────> VME
│
│
( ed altre applicazioni )
│─────> FASTBUS
.
└───────────────────────────────────┘─────> ECC.
.
.
!----------------------------------------------------------------------INTRODUZIONE
════════════
Il campo dei calcolatori elettronici e' forse quello che piu' di
tutti negli ultimi decenni ha mostrato un progresso sfrenato.
Infatti non solo ha raccolto i frutti del rapidissimo progresso
della microelettronica, ma ha anche contribuito al progresso della
nostra societa' con le grandi innovazioni nel campo del software e
della telematica.
Questo enorme progresso, unito alla grande rapidita' di evoluzione
di idee e sistemi, condiziona a nostro parere le modalita' di una
didattica istituzionale in questa materia. Infatti, mentre da un
lato gli studenti sono desiderosi di arrivare rapidamente all'apprendimento delle macchine e sistemi piu' moderni, dall'altro questi
non risultano adatti ad un efficiente apprendimento di base della
materia, poiche' mentre sono destinati ad una rapida obsolescenza,
inevitabilmente la loro complessita' pone degli ostacoli, complicando
e rallentando inutilmente la comprensione dei concetti di base, la
cui acquisizione, anche se fatta in maniera piu' semplice, permette
poi di capire meglio e piu' rapidamente il funzionamento non solo dei
sistemi attuali (che hanno una VITA LIMITATA) ma anche e soprattutto
di quelli futuri.
Per questi motivi nel nostro corso adotteremo come macchina di
riferimento il miglior processore tra quelli piu' semplici ad
8 bit prodotto alla fine degli anni settanta e addirittura lo
semplificheremo ulteriormente riducendone il numero dei registri
allo stretto indispensabile. In questo modo, per il nostro corso,
il processore ideale H6809 che ne deriva assume lo stesso ruolo
che il punto materiale svolge in Meccanica o che il gas perfetto
svolge in Termodinamica: un'idealizzazione che non ha riscontro
nella realta' ma che ci aiuta a comprendere i meccanismi che
stanno alla base della materia.
║
║
║
║
║
║
║
║
║
║
Per meglio comprendere i meccanismi di funzionamento impiegati nei
moderni calcolatori elettronici, pur nella loro complessita', seguiremo nella nostra trattazione un criterio di evoluzione 'storica',
con cui progrediremo con gradualita', dai sistemi uniprocessor con
sistema d'interruzione alla programmazione concorrente ed alla
multiprogrammazione per arrivare infine alle architetture avanzate
di elaborazione parallela multiprocessore.
Essendo nostra convinzione che un apprendimento di questa materia non
puo' essere disgiunto dall'acquisizione di capacita' operative sull'uso
dei computers, abbiamo associato alle lezioni teoriche delle esercitazioni pratiche svolte su personal computer dotati di un programma simulatore che fa funzionare il PC come se dentro ci fosse un processore
H6809. In questo modo lo studente puo' meglio comprendere i principi
della programmazione dei calcolatori elettronici che studia a lezione.
Un'ultima osservazione riguarda gli studenti del corso di laurea
║
in fisica, ai quali questo corso e' particolarmente diretto: come
║
deve essere gia' loro noto, la fisica si occupa di scoprire e stu- ║
diare le leggi fisiche della Natura ovvero i rapporti quantitativi ║
che intercorrono tra le grandezze osservabili, cioe' suscettibili
║
di misurazione e quindi quantificabili con numeri: per questo,
║
come la matematica ed i calcoli numerici hanno un ruolo fondamentale║
in fisica, cosi' anche i calcolatori elettronici sono fondamentali ║
per i fisici, come strumenti di calcolo (OFF-LINE).
║
Inoltre i calcolatori elettronici sono anche l'elemento centrale di ║
analisi e controllo in linea (ON-LINE) di tutti i moderni apparati ║
sperimentali e vanno quindi visti come parte essenziale dello stru- ║
mento con cui il fisico misura le grandezze fisiche osservabili,
║
che sono oggetto della fisica sperimentale.
║
Cosi' lo studio dei calcolatori elettronici e dei loro campi e
modalita' di impiego va associato allo studio dei trasduttori della
informazione fisica (per esempio i rivelatori di particelle), ed alle
metodologie di acquisizione ed analisi dei dati sperimentali, che
concorrono a formare lo strumento con cui indaghiamo il mondo fisico.
!----------------------------------------------------------------------AVVERTENZE IMPORTANTI PER LE ESERCITAZIONI
==========================================
Licenza d'uso: Le dispense per loro natura devono fare riferimento ai
libri di testo consigliati, sui quali lo studente puo'
cosi' trovare, in modo omogeneo, le informazioni per
gli ulteriori approfondimenti. Cio' e' stato fatto dal
docente con la massima attenzione al rispetto delle
disposizioni di legge sul diritto di autore e pertanto
il materiale didattico consegnato allo studente non
deve essere in nessun caso alterato ne' duplicato o
diffuso senza specifica autorizzazione scritta
dell'autore.
Il software contenuto nei dischetti consegnati dal
docente e' di proprieta' dei rispettivi fornitori e
concesso in licenza all'Universita' di Roma-La Sapienza.
Puo' essere usato solo presso questa Universita' nel
rispetto delle relative licenze, sui computer assegnati
per le esercitazioni, per fini didattici e non puo'
essere ne' asportato ne' copiato con qualsiasi mezzo.
Lo stesso vale per il testo delle dispense, la cui
circolazione deve essere limitata agli studenti
iscritti al corso del prof.R.Biancastelli.
Eventuali responsabilita' civili e penali previste
dalle leggi vigenti, conseguenti al mancato rispetto
delle disposizioni impartite al riguardo dal docente
e dagli organi universitari, sono solo dei trasgressori.
Per il materiale scaricato dalla rete devono essere
sempre rispettate le restrizioni di copyright indicate
dai relativi fornitori.
Poiche' spesso tra gli studenti si subiscono questi
doveri come ingiuste vessazioni, il docente ritiene
utile esprimere la propria opinione al riguardo: nei
Paesi in cui e' consentito a liberi imprenditori di
investire nella ricerca sul software, ripagandosi poi
degli investimenti fatti con i GIUSTI proventi della
vendita, una efficace tutela giuridica del software
e dei diritti di autore permette, al Paese che la
pratica, di sviluppare l'industria del software e di
creare con essa numerosi posti di lavoro, che in prospettiva valgono molto di piu' del software trafugato
(purche' le Autorita' sappiano contrastare le tendenze
ai monopoli nel software per salvaguardare, con la
concorrenza, il livello e la giustezza dei prezzi).
Virus: Le esercitazioni si svolgeranno usando un dischetto personale
per ogni studente: su questo dischetto vi saranno sia il file
contenente le dispense del corso, che appunti (LEZ??.PAS) e
programmi per le esercitazioni.
Lo studente dovra' riconsegnare questo dischetto al docente al
termine delle esercitazioni e non usare dischetti propri per
ragioni di sicurezza e protezione dai 'virus'. Un virus e'
un programma nascosto all'interno di un altro programma usato
dell'utente. Quando viene lanciato in esecuzione esso modifica
gli altri programmi eseguibili presenti sul dischetto e nel
computer installandosi in maniera invisibile nella memoria e
nel sistema operativo, in modo da rimanere stabilmente installato nella macchina, che risulta cosi' 'infettata' ed in grado
di infettare tutti i programmi eseguibili presenti sui dischetti di utenti ignari. Questo processo di contagio dei dischetti
del nostro corso e' possibile anche nei vari computers dei
nostri laboratori, poiche' sono aperti a tutti e qualcuno puo'
portare dischetti infetti dall'esterno.
I vostri dischetti, una volta infettati, se portati fuori del
laboratorio possono infettare il vostro computer dell'ufficio,
di casa, ecc.
Per questi motivi lo studente deve riconsegnare il suo dischetto al
docente al termine delle esercitazioni e non portare mai dischetti
propri in laboratorio.
I tecnici di laboratorio sono i custodi responsabili del funzionamento
e del coordinamento nell'uso dei computer. Gli studenti devono pertanto
attenersi alle disposizioni da essi impartite e segnalare loro eventuali
anomalie riscontrate.
PROGRAMMA DI LAVORO DURANTE LE ESERCITAZIONI PRATICHE:
-----------------------------------------------------Lo svolgimento delle esercitazioni e' basato sul materiale didattico
nel dischetto consegnato dal professore e su software scaricabile
gratuitamente da Internet (dopo essersi registrati indicando il proprio
indirizzo di E.mail: se non lo avete potete richiederlo ad un fornitore
di servizio gratuito di posta elettronica, per esempio Netscape).
Bisognera' quindi, al momento stabilito dal professore, eseguire il
download dei programmi seguenti, dai siti indicati:
Delphi
www.borland.com
(eserc. Pascal)
Java Development Kit
http://java.sun.com
(eserc. Java)
Perl
www.activestate.com
(eserc. CGI)
Apache Web-Server
www.apache.org/httpd
(eserc. Web)
vedi http://httpd.apache.org/docs/windows.html#req
(su Win95 potrebbe essere necessario scaricare anche l'upgrade
Winsock2 da http://www.microsoft.com/windows95/downloads)
Il programma di lavoro, configurato in base alla preparazione dello
studente, dovra' contenere, nell'ordine, i seguenti argomenti:
1) Uso dei comandi elementari del Sistema Operativo MS-DOS
2) Uso dell'Editor del TURBOPASCAL
3) Prove di uso delle istruzioni Pascal in semplici programmi (xxxDEMO.PAS)
4) Comprensione ed ampliamento del programma ADDING.PAS
5) Studio del programma Monitor
6) Studio del programma di simulazione H6809BUG.PAS (con BINPROG.PAS);
ricerca ed eliminazione degli errori ivi contenuti
7) Studio del microcomputer H6809 simulato su IBM-PC, scrivendo ed eseguendo
un semplice programma in linguaggio macchina
8) Ampliamento del simulatore H6809 introducendovi altre istruzioni come
quelle di branch condizionato o di I/O o il sistema d'interruzione
9) Uso dell'Editor dell'ambiente JDK1.3 (Java Developmenti Kit)
10) Prove di uso delle istruzioni Java in semplici programmi (xxxdemo.java):
FirstSample, Welcome, BigDebt, Test0, Root, NewRoot, SwapTest, SwapTest2,
ShellSort, VirusLook,
LotteryOdds: esempio con input da tastiera e chiamata a metodo
EmployeeTest,
H6809g: Monitor H6809 scritto in java
Root, RootApplet: esempio di applet
Prova: programma contenente un errore da trovare
11) Studio del programma Monitor H6809g.java, con particolare attenzione
all'uso dell' oggetto Byte (esempio di programmazione ad oggetti)
12) Realizzazione in Basic di un simulatore dello scattering coulombiano
con il metodo di Montecarlo
13) Programmazione concorrente del Montecarlo su una LAN in elaborazione
parallela ('farm' di computer).
14) Istallazione ed uso del Web server Apache con uso di applet Java e
script CGI.
15) Programmazione concorrente su rete Intranet (facoltativo).
AVVERTENZA IMPORTANTE
=====================
Le esercitazioni si svolgeranno usando un dischetto personale
per ogni studente: su questo dischetto vi saranno sia il file
contenente le dispense del corso, che appunti (LEZ??.PAS) e
programmi per le esercitazioni.
Gli esercizi e le dispense su Internet, sulla programmazione ad
oggetti e sul linguaggio Java saranno consegnati agli studenti
all'inizio del modulo B (subito dopo Pasqua).
Lo studente dovr? riconsegnare questo dischetto al docente al
termine delle esercitazioni e non portare dischetti propri per
ragioni di sicurezza e protezione dai 'virus'. Un virus e' un
programma nascosto all'interno di un altro programma usato
dell'utente. Quando viene lanciato in esecuzione esso modifica
gli altri programmi eseguibili presenti sul dischetto e nel
computer, installandosi in maniera invisibile nella memoria e
nel sistema operativo in modo da rimanere stabilmente installato
nella macchina. Questa risulta così 'infettata' ed in grado di
infettare tutti i programmi eseguibili, presenti sui dischetti
in essa inseriti da utenti ignari . Questo potenziale processo
di contagio dei dischetti del nostro corso e' possibile sia nei
computers del nostro laboratorio che in quelli del CATTID,
poiche' sono centri aperti a tutti e qualcuno puo' portare
dischetti infetti dall'esterno.
I vostri dischetti, una volta infettati, se portati fuori dall'Universita' possono infettare il vostro computer di casa,
dell'ufficio, ecc.
Per questi motivi lo studente deve riconsegnare il suo dischetto al docente al termine delle esercitazioni e non portare mai
dischetti propri al laboratorio o al CATTID.
!------------------------------------------------------------------Per le esercitazioni si puo' utilizzare anche la sala computers del
CATTID, dotata di 20 PC-IBM, ubicata come indicato nella piantina
seguente:
═════════════════════════════════════════════════════════════════
══
VIALE DEL POLICLINICO
═════════════════════════════════
══════════════════════════════
....─────────────────┐
╔═════════════════════════╗
│
║
EDIFICIO
║
│
║
CATTID
║
│
║ <--- ingresso
║
...──────────────────┘
╚═════════════════════════╝
...──────────────────┐
┌───────────────────────...
│
│
│
│ MINERALOGIA
GEOLOGIA
│
│
SCIENZE
│
│
│
POLITICHE
└────────────────────────────┘
│
│
───┐
┌───────────┘
F │
│
I │
│ GIURISPRUDENZA
S │
│
I │
└────┐
C │
Piazza
│
A │
della
│ RETTORATO
───┘
Minerva
│
!-----------------------------------------------------------I primi 9 capitoli sono contenuti nel file Corso_A.TXT (Modulo A)
!------------------------------------------------------------------CAPITOLO 10 - Programmazione concorrente
══════════
Riassunto: Scopo essenziale di questo capitolo e' quello di introdurre
le problematiche connesse con l'elaborazione simultanea di
piu' compiti (processi) da parte di uno stesso elaboratore,
quale si incontra per la prima volta usando il sistema di
interruzione.
⌡ 10.1 - Processi e loro stati
Il concetto astratto di 'processo' viene introdotto perche' aiuta a
capire il funzionamento dei programmi in ambiente di interruzioni
multiple.
Definiamo inizialmente un processo come un compito che l'elaboratore
svolge eseguendo le istruzioni di un apposito programma.
Vedremo in seguito (Java) che un processo puo' anche avere piu'
sottoprocessi (thread), funzionanti in concorrenza nella stessa
area di memoria virtuale del processo, ognuno con un compito
diverso, come per esempio quello di attendere il verificarsi di
un certo evento o di eseguire un'elaborazione compatibile con
la prosecuzione dell'elaborazione del programma (elaborazione
in background). Quando un thread termina il suo compito, viene
sospeso o eliminato.
Nel capitolo precedente abbiamo visto come sia possibile, con
il pieno impiego del sistema d'interruzione, far compiere al
calcolatore elettronico piu' processi simultaneamente, come
elaborazione, input, output, acquisizione di dati sperimentali,
ecc.
Con il termine 'simultaneamente' intendiamo dire che il computer
esegue l'elaborazione contemporaneamente ad altri compiti, come
quelli relativi all'I/O, nel senso che, mentre l'elaborazione
procede, vengono serviti (durante le interruzioni) i vari dispositivi
che inviano le interruzioni (input, output, acquisizione-dati, ecc.),
in modo da farli funzionare tutti insieme alla loro massima velocita'
(cosa resa possibile dalla maggior velocita' della CPU), e cio'
'contemporaneamente' al procedere dell'elaborazione principale.
Nell'esempio citato diremo cosi' che i processi di elaborazione
principale, input, output ed acquisizione-dati (identificabili
come attivita' distinte della CPU) sono eseguiti in concorrenza
tra loro, nel senso che la CPU esegue le istruzioni necessarie
alla loro esecuzione, saltando dall'un processo all'altro, in
modo pilotato dal succedersi delle interruzioni (servite con
le priorita' stabilite dal programmatore).
Cosi' si riesce ad ottenere due risultati importanti:
1) far lavorare ogni dispositivo alla sua massima velocita'
2) ridurre i tempi morti solo a quelli necessari al salto da un
processo all'altro ed al salvataggio e ripristino dello stato
della macchina all'interruzione.
Dopo aver definito un processo, vediamo di definire i suoi tre
stati possibili.
STATI DI UN PROCESSO:
1) inattivo
(=inactive)
2) attivo sveglio (=active awake)
3) attivo dormiente (=active asleep).
Consideriamo per esempio il processo di output di un messaggio
sulla console dell'operatore (i relativi programmi Assembly e
Pascal sono stati discussi nel capitolo precedente).
Prima che il processo di elaborazione principale (main program)
generi il messaggio, il processo di output e' nello stato inattivo.
Quando la CPU genera il messaggio, attiva anche il processo di
output, inviando (con il driver di output) il primo carattere
alla console ed attivando l'interruzione relativa (vedi ⌡ 9.7.2,
dove la variabile BUSY=1/0 indica lo stato attivo/inattivo del
processo di output).
La CPU ritorna poi al processo di elaborazione principale.
Da quel momento il processo di output e' nello stato attivo e
dormiente (in attesa di risveglio, quando arrivera' il segnale
d'interruzione, dopo il completamento della stampa del primo
carattere).
Successivamente, quando l'interruzione arriva (dopo che il primo
carattere e' stato stampato), la CPU interrompe il processo di
elaborazione principale, che va cosi' nello stato attivo dormiente,
e salta alla routine di servizio dell'interruzione, cominciando
ad eseguire le istruzioni del processo di output: in questo
momento diremo che il processo di output e' nello stato attivo e
sveglio.
Quando poi la routine di servizio dismette l'interruzione,
eseguendo l'apposita istruzione RTI (return from interrupt), il
processo di output torna nello stato attivo dormiente, mentre
il processo a cui si ritorna va nello stato attivo sveglio.
In conclusione abbiamo definito i tre stati di un processo nel
modo seguente:
┌───> DORMIENTE
---┐
│ (esecuzione sospesa)
|
INATTIVO <───> ATTIVO <───┤
| interrupt
│
|
└───> SVEGLIO
<---┘
(in esecuzione)
INATTIVO: quando un processo non e' ancora iniziato;
ATTIVO E SVEGLIO :
un processo iniziato ed in esecuzione (cioe' la
CPU ne sta eseguendo le istruzioni);
ATTIVO E DORMIENTE: un processo iniziato, ma in attesa di essere
continuato al momento dell'arrivo dell'interruzione
(la CPU sta eseguendo le istruzioni di un altro
processo).
In ambiente multiprocessor possono essere svegli piu' processi
contemporaneamente (con un solo processor un solo processo e' sveglio:
quello su cui la CPU sta lavorando).
MULTITASKING: Si possono anche attivare piu' processi di elaborazione,
anziche' di I/O, ed averne l'elaborazione 'simultanea', nel modo sopra
descritto, se si crea un apposito programma supervisore (chiamato
sistema operativo multitask o real time executive per le applicazioni
in tempo reale), appositamente progettato per coordinare l'esecuzione
dei vari processi, gestendone eventualmente anche le relative priorita'.
In questo caso le interruzioni che fanno passare la CPU da un processo
all'altro, possono essere non solo quelle generate dalle unita' di I/O,
ma anche quelle generate da:
- un 'real time clock' interno al calcolatore che, ad intervalli
di tempo prefissati, invia segnali di interruzione (time sharing);
- chiamate di sistema che sono inserite nel processo corrente per
evitare che questo faccia perdere tempo alla CPU restando in un
loop, in attesa che un altro processo si compia (vedi prossimo
esempio).
Si dice pre-emptive (cooperativo) un sistema operativo multitasking a
partizioni di tempo (time-sharing), in cui la CPU assegna il controllo
in ogni intervallo di tempo (time-slice) ad un task diverso e puo'
interrompere un processo in corso, salvandone lo stato, per eseguirne
uno piu' prioritario (riprendendo poi quello interrotto da punto in cui
era).
Nel multitasking non pre-emptive invece, quando un processo ottiene il
controllo della CPU non puo' piu' essere interrotto e tiene il controllo
finche' non e' terminato.
⌡ 10.2 - Programmazione dei processi - Sezioni critiche
Per poter programmare i processi abbiamo bisogno di apposite istruzioni
per dichiarare, risvegliare o mettere a dormire un processo.
In Pascal queste possono essere indicate con le seguenti parole
chiave (in maiuscolo):
PROCESS nome_del_processo; (Dichiarazione di processo)
WAKEUP nome_del_processo; (Risveglio di un processo)
SLEEP UNTIL condizione; (Messa a dormire condizionata del processo)
SLEEP;
(Messa a dormire incondizionata del processo)
In tal caso si parla di Pseudo-Pascal o Pascal concorrente.
Come esempio di programmazione che usa queste nuove istruzioni
esaminiamo quello che riporta i driver di I/O sotto interruzione
gia' studiati nel ⌡ 9.7.2 (Programmazione delle interruzioni):
PROGRAM ElaboraRighe (input,output);
.......
<--- Dichiarazione variabili
PROCESS RigaIn;
......
BEGIN
InputAvailable:=false; ClearInBuffer;
REPEAT
BEGIN
KbIEN:=true; KbGO:=true; KbRDY:=false;
SLEEP UNTIL KbRDY=true;
InBuffer(KbData)
END
UNTIL KbData=tappo;
InputAvailable:=true;
SLEEP
END;
Istruzioni nuove:
================
<----
PROCESS RigaOut;
......
BEGIN
OutPrinted:=false;
WHILE Buffer=pieno DO
BEGIN
DisplayData:=NextChar; DisplayIEN:=true;
DisplayGO:=true; DisplayRDY:=false;
PROCESS
SLEEP UNTIL
SLEEP
PROCESS
SLEEP UNTIL DisplayRDY:=true
END;
DisplayIEN:=false; OutputPrinted:=true;
SLEEP
END;
END;
PROCESS RigaElab;
......
BEGIN
WAKEUP RigaIn;
SLEEP UNTIL InputAvailable;
...... Elabora riga ......
SLEEP UNTIL OutputPrinted;
WAKEUP RigaOut
END;
BEGIN
<--- Inizio Main Program
OutputPrinted:=true; <--- Inizializzazione
WAKEUP RigaElab;
<--- Input+Elabora+Print
........
END.
SLEEP UNTIL
SLEEP
PROCESS
WAKEUP
SLEEP UNTIL
SLEEP UNTIL
WAKEUP
WAKEUP
In questo esempio i processi funzionano come coroutines, in quanto
quando sono risvegliati riprendono l'elaborazione dal punto in cui
erano stati sospesi (con SLEEP).
Questo fa capire come il compilatore deve tradurre in linguaggio
macchina le parti di programma dichiarate come processi.
⌡ 10.3 - Sezioni critiche, errori timing-dependent
La programmazione concorrente, in cui la CPU ripartisce il tempo di
elaborazione tra piu' processi contemporaneamente attivi, presenta
una problematica nuova.
Per coprenderne l'origine, consideriamo un esempio: un processo in
corso di elaborazione (attivo), tra un risveglio ed un altro puo'
trovarsi inopinatamente variati i valori di alcune variabili
memorizzate, perche' condivise con altri processi che sono entrati
in elaborazione mentre lui era dormiente ed hanno usato quelle
stesse variabili, cambiandone il valore.
Le aree di programma dove sono utilizzate le variabili (o piu' in
generale le risorse) condivise si chiamano 'sezioni critiche'.
Questi problemi non solo possono creare errori di elaborazione, ma
possono anche paralizzare l'attivita' del calcolatore: in tal caso
si dice che si e' verificata una situazione di 'stallo' (dead-lock),
in cui due processi si arrestano, ognuno in attesa che l'altro
compia una certa azione.
Per capire come cio' possa succedere, consideriamo il seguente
esempio, in cui un processo MAIN preleva dati tramite un altro
processo INPUT e li elabora:
PROCESSO MAIN
PROCESSO INPUT
──────┬──────
──────────────
│
─ ─ ─> interrupt
│
┌─────┴─────┐
┌────────────────────────────────>┤
│ Legge dati│
│
┌──┴──┐
└─────┬─────┘
│
no┌──────┘ e' └──────┐ ┌────────┴───────────┐
│
┌──────────┤InputAvailable=true│ │InputAvailable:=true│
│
│
└──────┐ ? ┌──────┘ └────────┬───────────┘
│
┌──────┴─────┐
└──┬──┘
┌──┴──┐
│
│Preleva dati│
si │
┌────┘ e' └─────┐ no
│
└──────┬─────┘
│
│MainWaiting=true├───>┐
│ ┌──────────┴──────────┐ ┌───────┴─────────┐ └────┐ ? ┌─────┘
│
│ │InputAvailable:=false│ │MainWaiting:=true│
└──┬──┘si
│
│ └──────────┬──────────┘ └───────┬─────────┘
┌────────┴─────────┐
│
│
┌──────┴─────┐
┌----->│
│MainWaiting:=false│
│
│
│Elabora dati│
| ┌────┴─────┐
└────────┬─────────┘
│
│
└──────┬─────┘
| │SLEEP Main│
┌─────┴─────┐
│
└<───────────┘
| └──────────┘
│WAKEUP Main│
│
|
└─────┬─────┘
│
Se interrupt avviene -----┘
├<────────────┘
qui', Main va in SLEEP con
┌─────┴─────┐
MainWaiting cambiato in false
│SLEEP Input│
da Input; cosi' Input non
└───────────┘
eseguira' mai piu' WAKEUP Main
ed entrambi i processi dormiranno
per sempre (situazione di stallo)!
Il punto indicato e' una sezione
critica perche' usa una variabile
condivisa (MainWaiting).
E' istruttivo esaminare anche altri casi in cui si puo' verificare
lo stallo. Un primo esempio e' quello in cui due processi per
lavorare si condividono le stesse pagine di memoria, richiedendole,
di volta in volta, al sistema di allocazione dinamica del sistema
operativo (non ci sono pagine di memoria sufficienti da allocare
ad entrambi i processi).
In questo caso si verifica uno stallo quando il processo B non puo'
procedere se non termina il processo A, il quale pero' non puo'
terminare perche' la memoria che gli sarebbe necessaria e' stata
gia' allocata a B (e rimane percio' per sempre in attesa che venga
rilasciata).
Si puo' verificare uno stallo anche nell'uso incorretto del bloccaggio
di risorse condivise tramite semafori. Per esempio, due processi di
compilazione di ordini, composti da articoli contenuti in records
di un file random, da parte di due distinti operatori, possono andare
in stallo se:
- il primo processo accede al record dell'articolo A bloccandolo
(perche' ne dovra' cambiare la giacenza all'invio dell'ordine);
- il secondo processo accede al record dell'articolo B bloccandolo;
- successivamente il primo processo chiede di accedere anche lui
all'articolo B (bloccato) ed il secondo processo chiede poi di
accedere all'articolo A, bloccato anch'esso (perche' li devono
inserire nei rispettivi ordini);
Ovviamente essendo gli articoli A e B gia' bloccati, l'accesso non
viene concesso ed i due processi vanno a dormire per sempre perche'
nessuno dei due rilascera' il bloccaggio del record che ha impegnato.
La procedura corretta sarebbe quella in cui ogni processo compila
l'ordine, bloccando poi i records o addirittura l'intero file (per
un tempo brevissimo, durante l'aggiornamento delle giacenze), con
un'unica operazione non interrompibile, solo all'invio dell'ordine.
Questo tipo di errori sono assolutamente da evitare (con un'attenta
progettazione e conoscendo i casi in cui possono verificarsi), perche'
essendo timing-dependent, producono effetti non riproducibili.
Cio' accade in quanto essi dipendono dall'istante di tempo in cui
arriva l'interruzione che mette a dormire un processo e ne risveglia
un altro: questo e' un evento non riproducibile nel senso che ripetendo
la procedura l'interruzione non ricapitera' nello stesso microsecondo
della volta precedente.
Puo' cosi' capitare che un programma sembra funzionare correttamente;
una volta reso operativo pero' mostra un'anomalia sporadica, che
compare casualmente nel senso che, ripetendo le operazioni con le
stesse modalita', l'anomalia non si ripete (perche' e' molto poco
probabile che l'interruzione responsabile dell'anomalia interrompa
il processo esattamente nello stesso istante, in cui la CPU sta
elaborando le istruzioni della sezione critica; anzi piu' breve e'
la sezione critica tanto meno sara' questa probabilita' e quindi
la riproducibilita' dell'anomalia).
⌡ 10.4 - Controllo delle sezioni critiche: bloccaggio e semafori
Abbiamo definito 'sezioni critiche' quelle parti del programma,
che fanno riferimento a variabili condivise con altri processi e
che pertanto possono variare in modo incontrollato in conseguenza
di interruzioni che avvengono durante l'esecuzione delle istruzioni
della sezione critica.
Nella programmazione dei processi concorrenti e' percio' necessaria
un'accurata analisi in fase progettuale di tutti gli eventi che
possono verificarsi.
Un primo modo di risolvere questi problemi, evitando stalli ed altri
errori timing-dependent (molto difficili da diagnosticare), e' il
BLOCCAGGIO ovvero l'accorgimento di impedire le interruzioni nelle
sezioni critiche (per questo basta disabilitare temporaneamente il
sistema d'interruzione).
Questo rimedio, benche' semplice da attuare, non e' pero' privo di
rischi: infatti e' possibile che la stessa disabilitazione del
sistema di interruzione in una sezione critica possa generare stallo,
se nella sezione critica c'e' un'istruzione di SLEEP, per esempio per
l'attesa di un'input. Lo stallo si verificherebbe perche' il processo
andato a dormire non si risveglierebbe mai piu', essendo l'interrupt
disabilitato; cosi', non uscendo piu' dalla sezione critica, non si
riabiliterebbe piu' il sistema d'interruzione disabilitato prima
di entrare nella sezione critica.
Un altro modo di proteggere le sezioni critiche del programma e'
quello di regolare con SEMAFORI l'accesso alle risorse condivise,
in modo che un solo processo alla volta possa usarle.
Un semaforo e' una variabile condivisa che puo' assumere due valori
(1=rosso e 0=verde). Basta fare un test su questa variabile prima
di entrare nella sezione critica: se e' rosso non si entra (si attende
o si mette in SLEEP il processo), se e' verde lo si mette rosso e si
entra nella sezione critica impegnando la risorsa condivisa.
La procedura e' descritta nel seguente diagramma:
┌──────────────>┤
Risorsa bloccata │
┌──┴──┐
da altro processo │
no ┌─────┘ e' └─────┐
└──────┤ SEMAFORO=verde │
└─────┐ ? ┌─────┘
si└──┬──┘
│ <-------- interrupt ?
┌───────┴───────┐
│SEMAFORO:=rosso│
└───────┬───────┘ ─┐
┌───────┴───────┐ │
│Uso risorsa
│ │
└───────┬───────┘ │ Risorsa bloccata
┌───────┴───────┐ │ da questo processo
│SEMAFORO:=verde│ │
└───────┬───────┘ ─┘
ecc.
Attenzione pero': un interrupt, che arrivasse mentre l'elaborazione
e' nel punto indicato dalla freccia, consentirebbe ad un altro processo
di impegnare la risorsa (perche' SEMAFORO non e' ancora stato posto
rosso) e ritornare dall'interruzione mantenendola ancora impegnata,
cosicche' entrambi i processi la userebbero contemporaneamente.
Per evitare questo, Test e Set del SEMAFORO devono essere fatti con
un'unica istruzione indivisibile (come TSET, ISZ, DSZ, ecc.), oppure
con un software interrupt, in cui si lascia disabilitato il sistema
d'interruzione (senza mettere ovviamente istruzioni di SLEEP nel
servizio dell'interruzione).
⌡ 10.5 - Condivisione di strutture-dati
Le stesse problematiche si incontrano se le risorse condivise sono
strutture di dati, scritte su disco.
E' necessario evitare i seguenti errori:
1) Mentre il processo A sta leggendo, il processo B interrompe e
aggiorna la struttura-dati;
2) Mentre il processo B sta scrivendo, il processo A interrompe per
leggere;
3) Mentre un processo sta scrivendo, l'altro interrompe e scrive
anche lui.
N.B. Nessun errore avviene invece se i due processi leggono
simultaneamente una stessa struttura-dati.
Il bloccaggio in lettura o scrittura a livello di file o record,
dev'essere messo a disposizione dal sistema operativo nei comandi
di accesso ai dischi (file system) e serve a proteggere la strutturadati.
Criteri analoghi si applicano a strutture-dati condivise su reti
locali LAN o in ambiente di multiprocessing (un'apposita esercitazione
mostrera' l'uso di questo bloccaggio nella realizzazione di una farm
di computers per elaborazione parallela in rete locale).
⌡ 10.6 - Condivisione di istruzioni. Programmi rientranti.
La condivisione di istruzioni e' possibile, senza che produca errori,
se il codice del programma e' scritto in maniera rientrante.
Per essere rientrante un sottoprogramma deve usare soltanto i registri
e lo stack per tutti i parametri e le variabili locali (come fa il
Pascal, ma non il Fortran, per esempio).
Devono inoltre essere evitate istruzioni automodificantesi durante la
elaborazione (ovvero il programma non deve costruirsi con istruzioni
di Store le successive istruzioni da eseguire): in altre parole il
codice del programma dev'essere 'read-only'.
Va inoltre evitata la memorizzazione di variabili in locazioni fisse
di memoria (perche' sarebbero sovrascritte da un secondo processo che
rientra nel sottoprogramma prima che il primo processo, che dorme
perche' e' stato sospeso da un'interruzione, ne sia uscito).
Il problema della generazione di codice rientrante e' gia' stata
discussa nel capitolo riguardante la descrizione dei modi di
indirizzamento.
I programmi rientranti sono importanti in ambienti multiprogrammati
perche' consentono di caricare nella memoria una sola copia delle
routines di utilita', che grazie alla rientranza risultano disponibili
simultaneamente a tutti gli utenti (per esempio: compilatori, text
editor, ecc.).
La programmazione concorrente e' facilitata dai moderni sistemi
operativi e compilatori che prevedono apposite facilities e restrizioni
che riducono il rischio di errori timing-dependent.
!----------------------------------------------------------------------CAPITOLO 11 - Sistema di memoria
═══════════
Riassunto: Scopo essenziale di questo capitolo e' quello di descrivere
gli accorgimenti messi in atto per migliorare le prestazioni
del sistema di memoria di un calcolatore elettronico e come
si possano poi risolvere i problemi connessi con il caricamento e l'elaborazione simultanea di piu' programmi nella
memoria dell'elaboratore.
⌡ 11.1 - Organizzazione gerarchica del sistema di memoria
Riportiamo in un'unico schema i vari elementi di memorizzazione usati
in un'elaboratore per confrontarne le caratteristiche (i valori indicano
solo gli ordini di grandezza):
COSTO ALTO
│
VELOCITA' ALTA
( $/Mb) ┌────────┴────────┐
│ CPU (registri) │ 1 ns
└────────┬────────┘
┌────────┴────────┐
5 $
│
CACHE MEMORY │ 10 ns
└────────┬────────┘
┌────────┴────────┐
1 $
│ MEMORIA PRIMARIA│ 100 ns
└────────┬────────┘
┌────────┴────────┐
0.1 $ │MEMORIA DI MASSA │ 10.000 ns
└────────┬────────┘
┌────────┴────────┐
0 $ │ MEMORIA IN RETE │ 1.000.000 ns
└────────┬────────┘
COSTO BASSO
│
VELOCITA' BASSA
Il divario tra la velocita' che si puo' rilevare tra la CPU e la
memoria rende determinanti le prestazioni del sistema di memoria.
Basta pensare che per ogni istruzione eseguita viene fatto almeno
un accesso alla memoria (fetch): per questo le prestazioni
dell'intero sistema di elaborazione vengono a dipendere dalle
prestazioni del sistema di memoria ed e' quindi molto importante
adottare tutti gli accorgimenti possibili per migliorarne le
prestazioni.
⌡ 11.2 - Tecniche di miglioramento delle prestazioni del sistema di memoria
Poiche' per ogni istruzione eseguita viene fatto almeno un accesso
alla memoria (fetch), le prestazioni del sistema di memoria determinano
le prestazioni dell'intero calcolatore elettronico.
Per questo motivo vale la pena esaminare dapprima alcuni semplici
accorgimenti che si possono adottare per velocizzare l'accesso alla
memoria.
1) Memory banking:
MSB
LSB
Bank 0
Bank 1
Bank 2
Bank 3
┌──────┬────────┐
0┌────────┐ 4┌────────┐ 8┌────────┐
12┌────────┐
│ Bank │ Offset │
1├────────┤ 5├────────┤ 9├────────┤
13├────────┤
└──────┴────────┘
2├────────┤ 6├────────┤ 10├────────┤
14├────────┤
Address
3└────────┘ 7└────────┘ 11└────────┘
15└────────┘
Dividendo la memoria in banchi elettronici diversi (banking), si
puo' avviare la lettura del fetch dell'istruzione seguente su un
banco, mentre un altro banco sta completando (per esempio) il ciclo
di scrittura che termina l'istruzione precedente.
Naturalmente il vantaggio scompare se il banco interessato dalle
due operazioni e' lo stesso (sarebbe come in assenza di banking).
In questo caso pero' ci viene incontro la tecnica dell'interleaving.
2) Memory interleaving: si ottiene dal memory banking semplicemente
collegando in maniera diversa le linee di indirizzamento:
MSB
LSB
Bank 0
Bank 1
Bank 2
Bank 3
┌──────┬────────┐
0┌────────┐ 1┌────────┐ 2┌────────┐
3┌────────┐
│Offset│ Bank │
4├────────┤ 5├────────┤ 6├────────┤
7├────────┤
└──────┴────────┘
8├────────┤ 9├────────┤ 10├────────┤
11├────────┤
Address
12└────────┘ 13└────────┘ 14└────────┘
15└────────┘
Usando i bit meno significativi come indirizzo del banco si ottiene
la distribuzione degli indirizzi indicata in figura. Siccome locazioni
di memoria contigue vengono ora a trovarsi su banchi distinti, risulta
molto piu' frequente che i cicli di memoria capitino su banchi diversi.
In questo modo si esalta il guadagno del memory banking.
3) Multiport memory: e' una tecnica costruttiva che consente all'elettronica del sistema di memoria di gestire piu' di un accesso simultaneo.
E' una tecnica particolarmente utile nei sistemi multiprocessore o nei
sistemi con I/O assistito da canale.
4) Multiword fetch: Siccome la fase di fetch dell'istruzione e' molto
onerosa, in quanto comporta un ciclo di lettura della memoria per
ogni istruzione eseguita, si puo' usare la tecnica di consentire
la lettura di 2 locazioni contigue per ogni ciclo di memoria.
Per esempio il computer IBM 370 eseguiva il fetch di 2 parole di
32 bit per ogni ciclo. In questo modo, se il successivo fetch era
in sequenza (cioe' se non veniva eseguito un salto), l'istruzione
era gia' pronta nei registri elettronici, senza bisogno di leggerla
dalla memoria con un ciclo di lettura.
5) Buffered Instruction Register: La tecnica del multiword fetch, che
mira a far trovare gia' pronta nei registri elettronici (molto piu'
veloci della memoria) l'istruzione da eseguire, puo' essere spinta
oltre, fino a prevedere un banco di molti registri elettronici che
vengono caricati con le istruzioni via via lette dalla memoria.
In questo modo nell'evenienza non improbabile di loop stretti si
possono trovare per molte volte le istruzioni gia' pronte nel banco
di registri, evitando cosi' di eseguire i cicli di lettura della
memoria, ben piu' lenti.
Lo schema di funzionamento, che prevede la funzione di 'freeze',
che congela il contenuto del buffer nel caso dei loop stretti, e'
il seguente:
┌─────────┐
Prefetch
┌────────┐
│ MEMORIA ├───────────────>│ BUFFER ├───>┐
└────┬────┘
┌───────>└────┬───┘
│
│
si│
│
│Fetch
│
╔══╗
Freeze│
│
│
no╔═══╝PC╚══╗
┌────┴───┐
│
└<─────║in Buffer║<───┤ CPU
│<───┘
╚═══╗ ?╔══╝
└────────┘
╚══╝
6) Tra gli accorgimenti hardware introdotti per migliorare le prestazioni
del calcolatore elettronico, riportiamo la tecnica del pipelining
(canalizzazione), anche se non riguarda direttamente il sistema di
memoria.
Si tratta di una tecnica che aumenta la velocita' di elaborazione,
introducendo un parallelismo interno alla CPU nell'esecuzione delle
istruzioni.
Per comprendere l'idea di base consideriamo il caso semplificato in cui
per compiere un'istruzione il calcolatore debba eseguire le tre fasi
seguenti, che hanno una certa durata temporale:
1) Fetch, che preleva l'istruzione dalla memoria;
2) Decode, che decodifica l'istruzione ed imposta gli organi interni
del calcolatore per eseguire l'istruzione;
3) Execute, che esegue l'istruzione.
Normalmente queste fasi andrebbero eseguite sequenzialmente (in serie
nel tempo), per cui per eseguire quattro istruzioni sono necessari
dodici passi:
Passo: 1
2
3
4
5
6
7
8
9
10
11
12
Fase : F1 + D1 + E1 + F2 + D2 + E2 + F3 + D3 + E3 + F3 + D3 + E3
Supponiamo ora di aver costruito l'elettronica del nostro calcolatore
in modo che le tre fasi possano essere eseguite indipendentemente.
E' allora possibile far lavorare le tre sezioni che eseguono Fetch,
Decode ed Execute in parallelo secondo lo schema seguente:
Passo : 1
2
3
4
5
6
Fetch : F1
F2
F3
F4
F5
F6
Decode :
D1
D2
D3
D4
D5
Execute:
E1
E2
E3
E4
7
8
ecc.
9
E' evidente come il parallelismo di funzionamento delle tre sezioni
del calcolatore permette di compiere il lavoro in un numero minore
di passi e quindi di far funzionare piu' velocemente il calcolatore.
Poiche' questo avviene facendo eseguire alla CPU il Fetch e Decode
dell'istruzione seguente prima della fine dell'Execute dell'istruzione
precedente, e' possibile (nei casi di istruzioni di salto) che questo
lavoro fatto, in cui la CPU cerca di avvantaggiarsi compiendo prima
il lavoro che si prevede di dover fare subito dopo, si inutile.
In questi casi (salti) il parallelismo del pipelining non funziona,
la 'pipe' si svuota e l'elaborazione procede con la solita velocita'
di una CPU non canalizzata per alcuni passi, finche' la 'pipe' si
riempie di nuovo. Questa situazione e' mostrata nello schema seguente,
in cui l'esecuzione dell'istruzione 3 esegue un salto:
Passo : 1
Fetch : F1
Decode :
Execute:
2
F2
D1
3
F3
D2
E1
4
*
D3
E2
5
*
*
E3
6
F4
*
*
7
F5
D4
*
8
F6
D5
E4
9
Come si puo' osservare dagli asterischi, lo svuotamento della 'pipe',
prodotto dall'istruzione di salto, provoca una sospensione temporanea
del funzionamento parallelo, con un conseguente rallentamento della
elaborazione.
⌡ 11.3 - Cache memory (ad indirizzamento diretto)
Per migliorare le prestazioni del sistema di memoria si possono sfruttare
le caratteristiche di localita' spaziale e temporale dell'elaborazione:
1) Localita' spaziale: in assenza di salti a lungo range, l'elaborazione tende a ripetere gli accessi alle stesse locazioni entro
un range limitato (basti pensare ai loop).
2) Localita' temporale: per gli stessi motivi il riutilizzo delle
stesse memorie avviene con alta probabilita' a breve distanza di
tempo.
Queste caratteristiche sono alla base del successo della tecnica di
accesso alla memoria con 'cache'.
L'idea e' quella di trattenere, caricandolo in una memoria ausiliaria,
non visibile al programmatore (cache=nascosta), che sia piccola ma molto
veloce, il contenuto (istruzioni e dati) delle locazioni lette nella
memoria principale, al fine di accedervi piu' rapidamente le volte
successive, se il dato e' ancora nella memoria cache. La localita'
spaziale e temporale rende molto frequente il successo di questo accesso
alla memoria cache.
Vediamo di comprenderne il funzionamento con un esempio di realizzazione
pratica (DEC Station 3100).
Lo schema seguente mostra il funzionamento una memoria cache da 16K,
organizzata in blocchi di 1 parola da 32 bit:
31
16 15
2 1 0
┌──┬──┬──┬──┬──┬──┬──┬──┬──┬──┬──┐
│ IDENTIF │ I N D I C E │
│ INDIRIZZO (sul memory bus)
└──┴──┴┬─┴──┴──┴──┴─┬─┴────┴──┴──┘
\16
\14
Byte
┌──────────┘
│
Addr.
│
┌────────────────┘
│
│
│
│
IDENTIF
DATO
│
│
FILL<--16 bit--> <---- 32 bit ---->
│
│
┌──┬────────────┬─────────────────┐ <─┐
│
│
│ │
│
│
│
│
│
├──┼────────────┼─────────────────┤
│
│
│
│ │
│
│
│
│
│
├──┼────────────┼─────────────────┤
│
CACHE
│
└───>│X │
*
│
*
│
│16Kword
│ Se X=0 non├|─┼─────|──────┼────────|────────┤
│
MEMORY
│ c'e' DATO │| │
|
│
|
│
│
│ in Cache ├|─┼─────|──────┼────────|────────┤
│
│
│| │
|
│
|
│
│
│
└|─┴─────|──────┴────────|────────┘ <─┘
│
|
\16
\32
│
|
│
|
│
|
╔══╩══╗
|
└────────────────>╣ = ║
└────> DATO
|
╚══╦══╝
│
└───>╔═════╗
└───────────>║ AND ╠───> OK (INDIRIZZO presente in cache)
╚═════╝
Ad ogni indirizzo corrisponde una locazione nella cache, individuata
dai 14 bit dell'INDICE. Questa corrispondenza non puo' essere biunivoca,
poiche' con i 32 bit dell'indirizzo possiamo indirizzare fino a 4Gword,
mentre la cache contiene solo 16Kword.
Poiche' 2 bit sono riservati per indirizzare i bytes, restano 16 bit
per l'identificatore e quindi esistono 2^16=64Kword indirizzi della
memoria, che si condividono una stessa locazione della cache.
Avendo scelto i bit piu' significativi come identificatore, questi
indirizzi della memoria disteranno tra loro di 64Kword: questo rende
possibile sfruttare la localita' spaziale dell'elaborazione, poiche'
ci garantisce un'adeguata permanenza del DATO nella cache.
Infatti funziona nel modo seguente:
- In lettura, se Presenza=True, si legge il DATO nella cache,
altrimenti si legge in memoria principale e si aggiorna il
DATO nella cache;
- In scrittura si scrive il DATO sia nella cache che in memoria
principale (modalita' Write-through).
E'
di
La
di
anche possibile organizzare la memoria cache in gruppi di 4 parole
32 bit, caricabili con un solo ciclo di accesso alla memoria.
figura seguente mostra una cache memory di 64K organizzata in blocchi
4 parole da 32 bit:
31 ...... 16 15 ........ 4 3 2 1 0
┌──┬──┬──┬──┬──┬──┬──┬────┬──┬──┬──┬──┐
│ IDENTIF │ I N D I C E │
│
│ INDIRIZZO (sul memory bus)
└──┴──┴┬─┴──┴──┴──┴┬─┴────┴──┼──┴──┴──┘
│
│
Word
Byte
\16
\12
Addr. Addr.
┌──────────┘
│
│
│
┌───────────────┘
└───────────────────────────────>─┐
│
│
│
│
│
IDENTIF
DATI
│
│
│
FILL<--16 bit--> <--------- 128 bit ----------->
│
│
│
┌──┬────────────┬───────┬───────┬───────┬───────┐
│
│
│ 0 │ │
│
│
│
│
│
│
│
│
├──┼────────────┼───────┼───────┼───────┼───────┤
│
│
│ 1 │ │
│
│
│
│
│
│
│
│ : ├──┼────────────┼───────┼───────┼───────┼───────┤ 4K
│
│
└───>│X │
*
│
*
│
*
│
*
│
*
│CACHE │
│
:
├|─┼─────|──────┼───|───┼───|───┼───|───┼───|───┤MEMORY│
│
: │| │
|
│
|
│
|
│
|
│
|
│
│
│
: ├|─┼─────|──────┼───|───┼───|───┼───|───┼───|───┤
│
│
4095│| │
|
│
|
│
|
│
|
│
|
│
│
│
└|─┴─────|──────┴───|───┴───|───┴───|───┴───|───┘
│
│
|
|
|
|
|
|
│
│
|
\16
\32
\32
\32
\32
\2
│
|
│
│
│
│
│
│
│
|
╔══╩══╗
╔═╩═══════╩═══════╩═══════╩═╗
│
└────────────────>╣ = ║
║
M U X
║<───────┘
|
╚══╦══╝
╚═════════════╦═════════════╝
|
│
│
|
│
\32
|
│
└──────>DATO
│
│
│
└───>╔═════╗
└───────────>║ AND ╠───> OK (INDIRIZZO presente in cache)
╚═════╝
Il funzionamento e' analogo alla cache precedente, pero' si caricano
4 parole (16 byte) per volta per sfruttare maggiormente la localita'
spaziale (per approfondimenti su questo argomento si veda D.Patterson,
J.Hennessy - Struttura e progetto dei calcolatori).
⌡ 11.4 - Memory Mapping & Management (Hardware)
Consideriamo un caso semplice con indirizzi a 16 bit.
Il MMU e' un dispositivo hardware che si inserisce sul bus degli
indirizzi per aumentarne il numero di linee e quindi il campo di
memoria indirizzabile. Per esempio si puo' estendere un address
bus da 16 bit a 20 bit, in modo da indirizzare 1M (20 bit) di
memoria fisica anziche' solo 64K (16 bit).
La conversione degli indirizzi da 16 a 20 bit dev'essere fatta
senza rallentare apprezzabilmente il ciclo di memoria (i tempi
di propagazione dei segnali elettronici nella MMU possono essere
trascurabili rispetto alla durata del ciclo di memoria).
Lo schema di principio e' il seguente:
┌───────┐
Data Bus
┌───────┐
│
│<══════════════════════════════════════════>│
│
│
│ Control Bus
│Memoria│
│
│═════════════════════════╦═════════════════>│
│
│
│
┌──┴──┐
│ Fisica│
│ CPU │ Address Bus
│ MMU │
│
│
│
│═══════════════/16═══>│(Map)│═══/20════════>│ ( 1M )│
│
│
Indir.Logico└──┬──┘Indir.Fisico
└───────┘
│
│
I/O Bus
║
│
│<════════════════════════╩═════════════════════════>...
└───────┘ (usato per caricare Map, come per I/O port)
La conversione degli indirizzi avviene prendendo i 4 bit da aggiungere
da uno degli 8 registri della MMU (Map): quello indirizzato dai 3 bit
piu' significativi dell'indirizzo logico.
Lo schema seguente mostra come avviene questa conversione:
15 13 12 ....
.... 2 1 0
┌─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┐
CPU ═══════> Indirizzo Logico │0 1 1│0 1 0 1 1 1 0 1 1 0 1 1 0│
(16 bit)
└─┴┬┴─┴─┴─┴─┴─┴─┴┬┴─┴─┴─┴─┴─┴─┴─┘
│
│
Map
│
│
┌─┬─┬─┬─┬─┬─┬─┬─┐
│
│
0 │W│0 0 0 0 1 1 0│
│
│
├─┼─┼─┼─┼─┼─┼─┼─┤
│
│
1 │W│1 1 0 1 1 0 1│
│
│
├─┼─┼─┼─┼─┼─┼─┼─┤
│
│
2 │W│0 0 0 1 1 1 0│
│
│
├─┼─┼─┼─┼─┼─┼─┼─┤
│
│
3 │W│0 0 0 1 1 1 1│<────────────┘
│
├─┼─┼─┼─┼─┼─┼─┼─┤
│
4 │W│1 1 1 0 1 1 0│
│
├─┼─┼─┼─┼─┼─┼─┼─┤
│
5 │W│0 0 0 0 1 1 0│
│
├─┼─┼─┼─┼─┼─┼─┼─┤
│
6 │W│0 0 0 0 0 1 1│
│
├─┼─┼─┼─┼─┼─┼─┼─┤
│
7 │W│0 0 0 0 0 0 0│
│
└─┴─┴─┴─┴┬┴─┴─┴─┘
┌<───────────────┘
│
│
19...
│ ...13 12....
│
....0
┌─┬─┬─┬─┬┴┬─┬─┬─┬─┬─┬─┬─┬─┬┴┬─┬─┬─┬─┬─┬─┐Indirizzo
MEMORIA
│0 0 0 1 1 1 1│0 1 0 1 1 1 0 1 1 0 1 1 0│ Fisico ════> FISICA
└─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┘ (20 bit)
Con la MMU si ottengono quindi 2 vantaggi:
1) Con il Memory Mapping si puo' montare una memoria fisica piu'
grande (1Mb) di quella massima indirizzabile (64K);
2) Con il Memory Management si possono caricare contemporaneamente
piu' programmi diversi (es. di 64K ciascuno) ed eseguirli senza
che interferiscano tra loro; infatti una volta caricati i registri
della Map, la CPU (attraverso gli indirizzi logici di 16 bit) puo'
accedere solo a quegli 8 blocchi di 8K ciascuno, individuati dai
contenuti caricati negli 8 registri della Map e non agli altri
(1024-64)K di memoria fisica.
Perche' la CPU possa elaborare un programma caricato in questa
memoria fisica non accessibile, basta che il sistema operativo
supervisore dell'elaborazione carichi nei registri della Map (con
le opportune istruzioni di I/O) gli indirizzi di altri 8 blocchi
di 8K (quelli dove sono istruzioni e dati del nuovo programma da
elaborare).
⌡ 11.5 - Verso il multitasking e la multiprogrammazione
L'introduzione della MMU, insieme al sistema d'interruzione, apre la
porta alla possibilita' del multitasking (piu' programmi dello stesso
utente elaborati simultaneamente, come in Windows 95/98) e della
multiprogrammazione (piu' programmi di utenti diversi elaborati
simultaneamente, come in Unix/Linux/Solaris, ecc.).
Vedremo tra poco, pero', come sara' necessario aggiungere degli
appositi accorgimenti hardware per permettere tutto cio' senza che
accadano anomalie di funzionamento. Per esempio, dev'essere impedito
che un utente possa compromettere il lavoro degli altri utenti, come
nel caso in cui uno studente che, esercitandosi nella programmazione
Assembly, esegua un programma che per errore cambia i registri della
MMU Map, cancellando cosi' la memoria usata da un altro utente.
In breve i problemi che bisogna risolvere e gli accorgimenti adottati
per risolverli sono i seguenti:
1) PROBLEMA: Impedire mutue interferenze tra utenti diversi:
----> Bisogna impedire che il programma di un utente possa variare
il contenuto dei registri di Map della MMU, mentre il
programma supervisore deve poterlo fare per impostare il
controllo della macchina sul lavoro di un altro utente.
Per ottenere questo si deve migliorare il progetto hardware
della CPU, aggiungentovi un flip-flop che definisce due stati
della CPU:
- SUPERVISOR MODE (flip-flop messo a 1): abilita l'accesso ai
registri della Map; la CPU e' in questo stato quando sta
eseguendo le istruzioni del programma supervisore.
- USER MODE (flip-flop messo a 0): la CPU viene mantenuta in
questo stato quando esegue le istruzioni del programma utente;
in tali condizioni la Control Unit impedisce alle istruzioni
del programma dell'utente di modificare i registri della MMU.
Poiche' non si puo' impedire che l'utente salti ad un'istruzione
che, se eseguita, modificherebbe il contenuto dei registri di
Map della MMU, bisogna anche modificare il funzionamento della
Unita' di Controllo, facendole produrre un'interruzione hardware
(Trap) se incontra l'esecuzione di una tale istruzione in User
mode (mentre non la deve produrre se la CPU e' in Supervisor
mode.
Un analogo tipo di restrizione dev'essere imposto all'utente
per impedirgli di accedere direttamente alle unita' periferiche
(perche' non si possano mescolare input/output di utenti
diversi: vedremo poi come i sistemi operativi multiutente
risolvono questo problema con il sistema di SPOOL).
Tutto cio' significa che:
RIMEDIO: -----> La CPU deve avere due modi di funzionamento (User e
Supervisor mode) e l'Unita' di Controllo deve
riconoscere un set privilegiato di istruzioni di I/O,
a cui consentire l'accesso soltanto in Supervisor mode
(se la CPU e' in User mode deve generare invece un trap
al tentativo di eseguirle).
2) PROBLEMA: Come vengono impostati il flip-flop di stato ed i registri
della MMU quando si accende il computer?
RIMEDIO : -----> Nella costruzione del computer bisogna prevedere un
metodo di inizializzazione hardware in Supervisor mode
e della Map della MMU perche' si possa procedere al
bootstrap (fase iniziale del caricamento del sistema
operativo).
3) PROBLEMA: Chi gestisce le interruzioni?
RIMEDIO : -----> Abbiamo gia' detto che l'I/O dev'essere controllato
in modo esclusivo dal sistema operativo, per cui sara'
prevista la commutazione automatica in Supervisor mode
all'arrivo di un'interruzione ed il controllo passera'
al sistema supervisore.
4) PROBLEMA: Restituzione del controllo al sistema operativo al termine
del lavoro di un utente (User mode), con commutazione dello
stato in Supervisor mode.
RIMEDIO : -----> Apposite istruzioni generatrici di interruzioni
software (che per questo si chiamano SYSTEM CALLS,
cioe' chiamate di sistema).
5) PROBLEMA: Cosa succede in caso di violazione delle regole da parte del
programma di un utente (per esempio: uso di istruzioni di I/O
o di altre che potrebbero minacciare l'integrita' del sistema
operativo)?
RIMEDIO : -----> Generazione da parte della CPU o della MMU di hardware
interrupts (=Trap).
6) PROBLEMA: Puo' anche accadere che l'utente faccia un uso non corretto
dello stack, restituendo al supervisore uno stack pointer
errato.
RIMEDIO : -----> Due stack separati per supervisore ed utenti (con due
registri di stack pointers diversi), per salvaguardare
l'integrita' dello stack del supervisore.
7) PROBLEMA: Come si puo' realizzare la condivisione di dati in memoria
tra utenti diversi, garantendo l'integrita' del sistema (per
farlo bisogna accedere alla Map della MMU)?
RIMEDIO : -----> Bisogna predisporre apposite utilities di sistema che
assolvono questo compito in maniera garantita.
8) PROBLEMA: Come possono gli utenti usare il DMA, in presenza della MMU?
RIMEDIO : -----> Ci sono due soluzioni possibili:
A) il DMA ignora la MMU, lavorando con indirizzi
fisici;
B) nei cicli DMA viene selezionata automaticamente
un'apposita Map, specificamente impostata per
l'attivita' di DMA.
Inoltre citiamo l'opportunita' di inserimento nella memoria di appositi
bit per ottenere gli scopi seguenti:
WRITE-PROTECT bit: permette di leggere ma non di scrivere nella locazione
di memoria (usate per proteggere il codice read-only
del sistema operativo)
EXECUTE-ONLY bit: permette di eseguire ma non di leggere la locazione di
memoria (leggibile solo durante la fase FETCH; usabile
per proteggere la segretezza del codice del sistema
operativo).
⌡ 11.6 - Gestione della memoria (Software)
PAGINAZIONE: La MMU permette di gestire la memoria in pagine che possono
essere assegnate ad un processo che ne ha bisogno e recuperate
quando il processo ha terminato di utilizzarle.
Questo presuppone un'attivita' di allocazione dinamica della
memoria, suddivisa in pagine, da parte del sistema operativo.
Per questo un'apposito modulo software viene predisposto, che
gestendo apposite tabelle, come quelle sotto riportate, che
rappresentano lo stato di allocazione delle pagine di memoria,
svolge questa funzione.
Blocchi disponibili:
BLOCCO│STATO
FISICO│ALLOCAZ.
─────┼─────
Blocchi allocati ai processi:
BLOCCO│BLOCCO│
LOGICO│FISICO│PROTEZ.
───────┼──────┼──────
<---- Processo
A
0
1
2
3
4
5
6
│
│
│
│
│
│
│
B
0 <---Blocco libero
0 <---Blocco libero
A
A
B
B
1
0
1
│
│
3
4
│ R/W
│ R
BLOCCO│BLOCCO│
LOGICO│FISICO│PROTEZ. <---- Processo B
───────┼──────┼──────
0 │ 0
│ E
(Execute only)
│ 5
│ R/W (Read/Write)
2
│
6
│
R
(Read only)
I processi lavorano con indirizzi logici contigui, mentre la
traduzione in indirizzi fisici viene eseguita dai circuiti
della MMU. Quando un processo dev'essere attivato il sistema
operativo guarda se ci sono i blocchi di memoria richiesti:
se ci sono, li alloca aggiornando le tabelle ed impostando
la Map della MMU, altrimenti risponde con 'allocazione negata'
ed il processo non viene attivato.
L'allocazione puo' essere fatta in due modi: a partizioni
fisse o vaariabili.
PARTIZIONI FISSE: I blocchi di lunghezza prefissata vengono allocati fino
al termine del processo che li ha richiesti.
PARTIZIONI VARIABILI: Come sopra, ma la frazione del blocco in eccesso
viene ridefinita come un nuovo blocco riusabile.
In questo modo aumenta continuamente il livello di
frammentazione dei blocchi, per cui dev'essere
prevista una procedura di ricompattamento che eviti
la loro eccessiva frammentazione.
⌡ 11.7 - Memoria virtuale
Sviluppando applicazioni si arriva non di rado ad aver bisogno di
una quantita' di memoria fisica di gran lunga superiore alla massima
disponibile sul nostro calcolatore elettronico.
La strada percorribile e' allora quella di segmentare l'applicazione
in piu' programmi, ognuno dei quali entra nella memoria disponibile,
e caricarli automaticamente in memoria, con apposite istruzioni messe
nel programma, quando occorre. Queste intruzioni di CHAIN caricano
solo il codice delle istruzioni lasciando inalterato lo stato dei
dati in memoria. Questa procedura e' meno complicata di quanto possa
sembrare, poiche' le applicazioni in genere constano di un menu'
con tanti comandi, ad ognuno dei quali il programmatore puo' far
corrispondere un modulo software diverso, gestito sotto CHAIN
(segmentazione del programma).
Questo tipo di soluzione e' pero' insoddisfacente perche' lascia al
programmatore l'onere della gestione della memoria (inserendo le
istruzioni di CHAIN nel proprio programma).
Molto meglio sarebbe se il programmatore potesse vedere una memoria
praticamente illimitata (reperendo lo spazio sui dischi), lasciando
al sistema operativo l'onere di gestire automaticamente i processi
di roll-in e roll-out di programmi e dati da memoria a disco e
viceversa.
Per ottenere questo viene inserita nel sistema operativo una nuova
funzionalita' (Memoria Virtuale), che consente di elaborare programmi
che richiedono una quantita' di memoria superiore a quella fisica
disponibile (ma inferiore alla memoria di massa disponibile).
Con questa tecnica tutti i blocchi necessari ad un processo in
esecuzione sono su disco e solo una parte di loro e' caricata in memoria
fisica. Quando un nuovo blocco X e' indirizzato dal programma, se esso
non e' nella memoria fisica, viene individuato il blocco meno usato,
tra quelli presenti in memoria, che viene salvato su disco per lasciare
posto al blocco X che dev'essere caricato in memoria.
Il processo che aveva bisogno del blocco viene sospeso (SLEEP) durante
il caricamento.
Questa tecnica permette di:
1) Tenere durante l'elaborazione dati e programmi su disco, usando la
memoria principale (RAM) come una 'cache' della memoria secondaria
(su disco); vedremo in seguito come questa a sua volta potra' fungere
da 'cache' della memoria costituita dai file condivisi in rete, per
evitare la ripetizione dello scaricamento da rete (lento) di un file
gia' memorizzato sull'hard disk locale (HD cache).
2) Superare i limiti della memoria fisica istallata (senza dover ricor-
rere a procedure di CHAIN gestite dall'utente).
Ripetiamo qui' lo schema di organizzazione gerarchica del sistema di
memoria presentato nel ⌡11.1:
COSTO ALTO
│
VELOCITA' ALTA
( $/Mb)
┌────────┴────────┐
│ CPU (registri) │ 1 ns
└────────┬────────┘
┌────────┴────────┐
5 $
│
CACHE MEMORY │ 10 ns
└────────┬────────┘
┌────────┴────────┐
1 $
│ MEMORIA PRIMARIA│ 100 ns
└────────┬────────┘
┌────────┴────────┐
Memoria Virtuale ---> 0.1 $ │MEMORIA DI MASSA │ 10.000 ns
****************
└────────┬────────┘
┌────────┴────────┐
0 $ │ MEMORIA IN RETE │ 1.000.000 ns
└────────┬────────┘
COSTO BASSO
│
VELOCITA' BASSA
Nello schema logico di funzionamento della memoria virtuale, gli
indirizzi (virtuali) su cui lavora il programma stanno parte in RAM
e parte su disco, come mostrato nello schema seguente:
FILL Indirizzi Virtuali
Indirizzi fisici
┌───┬──────────────────┐
┌───────────────┐
│ 0 -------------------│-----─┐
┌--->│
│
├───┼──────────────────┤
|
|
├───────────────┤
│ 1 -------------------│------|---|--->│
│
├───┼──────────────────┤
|
|
├───────────────┤
Memoria
│ 1 -------------------│------|--─┘
├───┼──────────────────┤
|
│
Memoria RAM │ Fisica
├───────────────┤
(RAM)
MEMORIA
│ 1 -------------------│------|------->│
│
VIRTUALE ├───┼──────────────────┤
|
├───────────────┤
(indirizzata│ 0 -------------------│---─┐ |
┌--->│
│
dal
├───┼──────────────────┤
| |
|
└───────────────┘
programma) │ 1 -------------------│----|-|--─┘
╔════════════╗
├───┼──────────────────┤
| └--------->║
║
│ 0 -------------------│--┐ └----------->║
HARD
║ Memoria
├───┼──────────────────┤ └------------->║
DISK
║ su
disco
│ 0 -------------------│---------------->║
║
└───┴──────────────────┘
╚════════════╝
Si noti come memoria virtuale e memoria fisica siano suddivise in
pagine.
Non tutte le pagine virtuali sono caricate in memoria RAM, ma solo
quelle indicate con FILL=1.
Nulla vieta che due o piu' indirizzi virtuali corrispondano allo
stesso indirizzo fisico: in questo modo e' possibile condividere
dati e istruzioni tra programmi diversi (assumendo che se ne faccia
poi un uso corretto, in base ai vincoli imposti dalla programmazione
concorrente).
Per la mappatura delle pagine tra virtuali e fisiche si puo' seguire
uno schema di traduzione degli indirizzi analogo a quello gia'
incontrato nel memory management della MMU: la differenza e' nel
fatto che in questo caso la memoria fisica e' supposta essere piu'
piccola (4Gb) di quella indirizzabile con l'indirizzo virtuale di
32 bit (16Gb).
31 ....
.... 12 11... ... 0
┌──────────────────────────┬────────────┐
│ NUMERO DI PAGINA VIRTUALE│ADDR.IN PAG.│ INDIRIZZO VIRTUALE
└─────────────┬────────────┴─────┬──────┘ (2^32x32bit = 16Gb)
\20
\12
│
│
╔════════════╗
│
║ TRADUZIONE ║
│
╚════════════╝
│
│
│
\18
│
29 ....
│
.... 12 11...│ ... 0
┌───────────┴────────────┬─────┴──────┐
│ NUMERO DI PAGINA FISICA│ADDR.IN PAG.│ INDIRIZZO FISICO
└────────────────────────┴────────────┘ (2^30x32bit = 4Gb)
256K pagine
Pagine di
(2^18=256K)
4K parole
(2^12=16Kb)
La gestione della memoria virtuale funziona quindi nel modo seguente:
quando la CPU invia un indirizzo (virtuale) per accedere ad un dato nella
memoria, possono verificarsi due casi.
1° caso: La pagina indirizzata e' in memoria principale: il meccanismo di
traduzione trasforma immediatamente l'indirizzo virtuale in
indirizzo fisico e la CPU accede al dato.
2° caso: La pagina indirizzata non e' presente nella memoria principale:
possono allora verificarsi due sottocasi:
a) Esiste una pagina di memoria libera e quindi disponibile al processo.
Allora il sistema operativo:
- genera una SYSTEM CALL "Pag.assente";
- blocca il processo (SLEEP);
- identifica, nel modo che descriveremo, la pagina sul disco e la
trasferisce da disco nella pagina disponibile della memoria
principale;
- al termine del trasferimento il processo potra' essere risvegliato
e lavorera' come descritto nel 1° caso (trovando ora la pagina in
memoria principale).
b) Non esiste una pagina di memoria libera, disponibile al processo.
Allora il sistema operativo, con un "Algoritmo di sostituzione"
appropriato, individua il blocco RAM meno usato (magari con hardware
aggiuntivo in grado di sfruttare la localita' temporale), lo salva
su disco (modalita' Write-back) e trasferisce poi la pagina richiesta
dal processo in queste locazioni della memoria principale (RAM).
Al termine, il processo potra' essere risvegliato e lavorera' come
descritto nel 1° caso.
Nella memoria cache avevamo adottato il metodo di scrittura detto 'Writethrough' (sul livello di gerarchia di memoria inferiore, cioe' in memoria
principale).
Nella memoria virtuale dobbiamo utilizzare invece sempre il metodo 'Writeback', cioe' il salvataggio operato al momento della sostituzione di pagina
nella memoria fisica) per la scrittura sul livello di gerarchia di memoria
inferiore (in questo caso i dischi), per l'eccessivo tempo di accesso.
Vediamo ora di capire con un esempio come puo' funzionare il meccanismo di
traduzione dell'indirizzo virtuale in indirizzo fisico.
Quando si avvia l'elaborazione di un processo, il sistema operativo alloca
al processo lo spazio di memoria necessario, sotto forma di un certo numero
di pagine di memoria virtuale.
La mappatura, degli indirizzi virtuali sulle pagine del disco, viene in
quel momento definita e scritta sul disco, sotto forma di una tabella
(TPD, Tabella delle Pagine su Disco), che memorizza la corrispondenza tra
gli indirizzi delle pagine virtuali ed gli indirizzi delle corrispondenti
pagine sul disco.
Un'analoga tabella (TPF, Tabella delle Pagine Fisiche) viene allocata su
RAM per memorizzare le corrispondenze tra gli indirizzi di tutte le pagine
virtuali indirizzabili dalla CPU ed i corrispondenti indirizzi fisici delle
pagine virtuali presenti su RAM, che saranno meno di quelle indirizzabili
(16Gb) perche' la memoria fisica nel nostro esempio e' solo di 4Gb.
Inizialmente TPF e' vuota, cioe' ha tutti FILL=0.
Quando la CPU comincia ad indirizzare la memoria virtuale, accede in modo
diretto ad una locazione della tabella TPF, utilizzando i 20 bit piu'
significativi dell'indirizzo virtuale (vedi lo schema seguente).
Trovando FILL=0, esegue le operazioni descritte al precedente punto 2a),
cioe' identifica sul disco, usando la tabella TPD scritta su disco, la
pagina richiesta e la trasferisce nella pagina disponibile della memoria
principale, scrivendo il relativo indirizzo fisico di pagina nei 18 bit
della tabella TPF e ponendo FILL=1.
Da quel momento, finche' in quella locazione di TPF rimarra' FILL=1, la
tabella TPF fungera' da tabella di mappatura di quella pagina virtuale
nella corrispondente pagina fisica, realizzando cosi' la traduzione degli
indirizzi da virtuali a fisici (per tutte le pagine caricate in RAM, con
FILL=1), tramite un semplice accesso di lettura alla tabella TPF in RAM.
In altre parole il blocco di memoria di 3Mb RAM, che abbiamo chiamato
TPF (Tabella delle Pagine Fisiche), svolge lo stesso ruolo che la
'Mappa' della MMU svolgeva per la traduzione degli indirizzi: soltanto
che ora la traduzione e' meno veloce, perche' la mappa non e' su registri
elettronici ma su RAM (essendo di 3 Mb).
Ogni programma deve avere un proprio spazio di indirizzi virtuali e quindi
una sua tabella TPF.
Si introduce allora anche un apposito registro hardware (Registro Tabella
Pagine), che consente di individuare l'inizio dell'area TPF della memoria
RAM dove, con i 20 bit del numero di pagina virtuale, memorizziamo il
numero di pagina fisica (di 18 bit), in cui e' stata caricata quella
pagina virtuale (vedasi lo schema seguente).
Cosi' alle interruzioni (commutazione di processo) non si dovra' salvare
tutta la tabella di 3 Mb, ma solo il relativo Registro, che indica
l'indirizzo iniziale della tabella TPF.
Al risveglio, ogni processo trovera' cosi' caricato in questo registro
l'indirizzo d'inizio della propria 'Tabella delle pagine' TPF e potra'
lavorare correttamente, usando la propria mappatura della memoria virtuale
nella memoria fisica.
Il sistema operativo provvede al caricamento delle pagine da disco su
RAM mettendo FILL=1 per indicare che la pagina virtuale indirizzata e'
presente in memoria RAM.
┌─────────────────────────┐
│ REGISTRO TABELLA PAGINE │ (contiene l'indirizzo iniziale di TP)
└─┬───────────────────────┘
│
│
31 ....
.... 12 11... ... 0
│
┌──────────────────────────┬────────────┐
│
│ NUMERO DI PAGINA VIRTUALE│ADDR.IN PAG.│ INDIRIZZO VIRTUALE
│
└────────┬─────────────────┴─────┬──────┘ (2^32x32bit =16Gb)
│
\20
\12
│
FILL
│
Num.di pag.fisica
│
│
┌────┬───│───────────────────┐
│
└───>│
│
│
│
│
├────┼───│───────────────────┤
│
│ X │
*
*
│
│
TABELLA DELLE PAGINE (TPF)
├─|──┼─────────│─────────────┤
│
(2^20x19bit = 3Mb)
│ | │
│
│
│
└─|──┴─────────│─────────────┘
│
N.B. Se X=0 la pag.
│
│
non e' in RAM
\18
│
│
│
29 ....
│
.... 12 11... │... 0
┌─────────────┴──────────┬──────┴─────┐
│ NUMERO DI PAGINA FISICA│ADDR.IN PAG.│ INDIRIZZO FISICO
└────────────────────────┴────────────┘( 2^30x32bit = 4Gb )
256K pagine
(2^18=256K)
Pagine di
4K parole
(2^12=4Kb)
Il prezzo da pagare per i benefici forniti dalla memoria virtuale e'
un rallentamento dell'accesso alla memoria, perche' sono necessari due
accessi alla memoria principale anziche' uno:
1) Un primo ciclo (lettura della 'Tabella delle pagine' TPF) per ottenere
l'indirizzo fisico (=traduzione);
2) Un secondo ciclo per ottenere il dato, leggendo l'indirizzo fisico.
Essendo la velocita' di accesso alla memoria un fattore determinante
per le prestazioni dell'intero sistema di elaborazione, vediamo come si
possono ridurre gli effetti di questo rallentamento.
Per velocizzare l'accesso in memoria virtuale si possono conservare i
risultati delle traduzioni degli indirizzi (da virtuale a fisico) in una
speciale memoria cache, chiamata TLB (Translation Lookaside Buffer).
Siccome il numero di pagina cercato puo' essere in una posizione qualsiasi
del TLB, la ricerca della LABEL (tipica della cache) conviene che sia
fatta con una memoria di tipo "associativo".
Se questa ricerca fallisce vuol dire che l'indirizzo della pagina fisica
non e' nel TLB e si deve quindi procedere alla lettura della relativa
locazione della TPF (tabella delle pagine fisiche) in memoria principale.
Il TLB (Transl. Lookaside Buffer) funziona come una cache della tabella
delle pagine, ma solo per gli indirizzi delle pagine fisiche.
Riportiamo lo schema di funzionamento di una memoria virtuale con TLB:
FILL LABEL INDIRIZZO PAGINA FISICA
┌───────────────┐
┌────┬─────┬───────────────────────┐
│ N.PAG.VIRTUALE│
│ 0 │
│
│
└───┬───────────┘
├────┼─────┼───────────────────────┤
TLB
├───────────────>│ 1 │
│
*
│ Es. 4Kb di
│
├────┼─────┼────────────────|──────┤ memoria
veloce
│
│ 1 │
│
| *
│ (associativa)
│
└────┴─────┴────────────────|─|────┘
│
| |
│
| |
Memoria Fisica
│
FILL Ind.Pag.Fisica/Disco
| |
(es. 4Gb di DRAM)
│
┌────┬────────────────────┐
| |
┌──────────────┐
│
│ 0 │
o --------│--------─┐
| └--->│
│
│
├────┼────────────────────┤
|
|
├──────────────┤
│
│ 1 │
* --------│---------|-─┐ └----->│
│
│
├────┼────────────────────┤
| |
├──────────────┤
└──>│ 1 │
* --------│---------|--|------->│
│
├────┼────────────────────┤
| |
├──────────────┤
TPF │ 0 │
o --------│------─┐ | └------->│
│
(Tabella├────┼────────────────────┤
| |
├──────────────┤
Pagine │ 1 │
* --------│-------|-|---------->│
│
Fisiche├────┼────────────────────┤
| |
└──────────────┘
es.3Mb │ 0 │
o --------│----─┐ | |
DRAM)├────┼────────────────────┤
| | |
│ 0 │
o --------│--─┐ | | |
└────┴────────────────────┘
| | | |
╔═╩═╩═╩═╩═╗
║ DISCO ║ Indirizzi su disco
╚═════════╝
Volendo si potrebbe segmentare in pagine anche lo spazio occupato dalla
tabella delle pagine TPF e gestire anche questa in memoria virtuale.
Questa soluzione risulta conveniente quando si riservano piu' di 20 bit
per l'indirizzo di pagina virtuale e quindi aumenta oltre 3 Mb lo spazio
richiesto per la Tabella delle pagine TPF oppure in quei sistemi che,
dovendo gestire centinaia di processi attivi contemporaneamente, avrebbero
gran parte della memoria fisica impegnata dalle centinaia di tabelle TPF
dei vari processi attivi.
Ovviamente anche per gli indirizzi fisici ricavati con lo schema della
memoria virtuale (e non solo per gli accessi alla 'Tabella delle pagine')
si puo' applicare la tecnica della memoria cache per velocizzare ulteriormente l'accesso.
Quello che segue e' lo schema di memoria virtuale con TLB e Cache Memory
realizzato nella DecStation 3100:
31 ....
.... 12 11... ...0
┌──────────────────────────┬───────────┐
│ NUMERO DI PAGINA VIRTUALE│ PAGE ADDR.│ INDIRIZZO VIRTUALE
└──────────┬───────────────┴─────┬─────┘ (2^32x32bit =16Gb)
\20
\12
┌────────────────────┘
│
│
FILL MODIF IDENT IND.PAG.FISICA
│
│
┌────┬─────┬─────┬──────────────┐
│
│
│
│
│
│
│
│
│
├────┼─────┼─────┼──────────────┤
│
├───>│ * │
│ * │
*
│TLB │
│
├─|──┼─────┼──|──┼────────|─────┤
│
│
│ | │
│ | │
|
│
│
│
└─|──┴─────┴──|──┴────────|─────┘
│
│
|
╔═╩═╗
\20
│
└──────|────────>║ = ║ Assoc. |
│
|
╚═╦═╝
|
│
| ┌─────────┘
|
│
╔═╩═╩═╗
┌─────┬───┴───────────┴───┐
║ AND ║
│IDENT│
INDICE
│ INDIRIZZO FISICO
╚══╦══╝
└──┬──┴─────────┬─────────┘
Addr in TLB
│
\14
│ ┌──────────┘
│ │
FILL IDENT
DATI
│ │
┌────┬─────┬──────────────┐
│ │
│
│
│
│
│ │
├────┼─────┼──────────────┤
│ └──>│ * │ * │
*
│ Cache Memory
│
├─|──┼──|──┼───────|──────┤
│
│ | │ | │
|
│
│
└─|──┴──|──┴───────|──────┘
│
|
╔═╩═╗
|
└───────|──>║ = ║
|
|
╚═╦═╝
|
| ┌───┘
|
╔═╩═╩═╗
|
║ AND ║
|
╚══╦══╝
|
Cache grant
DATO
(per ulteriori approfondimenti su questi argomenti si veda D.Patterson,
J.Hennessy - Struttura e progetto dei calcolatori: l'interfaccia hardware
software).
!----------------------------------------------------------------------CAPITOLO 12 - Sistemi operativi
═══════════
Riassunto: Scopo essenziale di questo capitolo e' quello di spiegare i
principi di base del funzionamento dei sistemi operativi.
⌡ 12.1 - Origine e requisiti necessari
----------------------------Dal grafo con cui nell'introduzione abbiamo presentato il collegamento
logico tra i vari argomenti trattati nel nostro corso, che riportiamo
qui' per comodita', possiamo vedere come tutti gli argomenti fin qui'
trattati conducano all'introduzione dei sistemi operativi (e di rete,
trattati nel prossimo capitolo):
ARCHITETTURA ELABORATORE
┌──────────────────────────┐
│
UNITA' CENTRALE
│
│
───────────────
│
┌───│<─ SISTEMA │ SISTEMA ──>│───┐
│
│
I/O
│ MEMORIA
│
│
│
└────────────┼─────────────┘
│
│
│
│
│
PROGRAMMAZIONE
│
│
(ASSEMBLY,PASCAL,JAVA...)
│
│
│
│
│
│
│
SISTEMA ────> PROGRAMMAZIONE
MEMORY
D'INTERRUZIONE
CONCORRENTE
MANAGEMENT
│
│
│
│
│
│
└─────> SISTEMI OPERATIVI <────────┘
MONOUTENTE
│
│
SPECIALI ACCORGIMENTI
HARDWARE
│
│
┌───────────┴───────────┐
│
SISTEMI OPERATIVI
│
│ MULTIUTENTE,MULTITASK │ <---- Punto in cui siamo
│
SOFTWARE DI RETE
│
******************
└───────────────────────┘
Un sistema operativo e' un programma scritto per fornire alle applicazioni
dell'utente un facile accesso a vari servizi, come quelli necessari per
eseguire operazioni di Input/Output (interfaccia di sistema).
Il sistema operativo fa quindi 'vedere' all'utente una macchina virtuale piu'
semplice e facile da usare.
I sistemi operativi possono essere di vari tipi:
- Dedicati: sono quelli concepiti per essere usati da un solo utente. Anche
quelli dei PC possono rientrare in questa categoria.
- Dedicati in rete: un'interfaccia software particolare puo' consentire di
facilitare l'accesso anche ai servizi di rete (locale o
geografica).
- A lotti (batch): fin dai primi sistemi operativi degli anni '60, si
automatizzavano le varie operazioni richieste al sistema
per eseguire un lavoro (lettura programma, compilazione,
link-editaggio, caricamento, lettura dati, esecuzione) con
dei macro-comandi che si inserivano come schede o come
righe di comando fornite all'interprete dei comandi da un
terminale di input. Il risultato e' il funzionamento di
un centro di calcolo in cui l'utente consegna un lavoro,
che viene poi letto ed eseguito come stabilito da uno
'scheduler'. I risultati sono disponibili all'utente al
termine.
- Interattivi (time-sharing): consentono a piu' utenti di lavorare
contemporaneamente sul computer dai terminali collegati
anche via modem, condividendosi il tempo della CPU in
piccoli intervalli di tempo (time slice=50msec, per
esempio);
- Controllo di processo (Real-time Executive): sono quelli dedicati alle
applicazioni in tempo reale, cioe' quelle in cui l'utente
vuole che siano soddisfatti dei vincoli sui tempi di
esecuzione dei vari task (non superiore a ....msec).
Campi di applicazione tipici sono il controllo on-line di
apparati industriali o sperimentali (come quelli usati dai
fisici).
- Transazionali: sono quelli concepiti per essere usati con un'applicazione
particolare.
Non potendo addentrarci nello studio dei sistemi operativi nel nostro corso,
cercheremo di capire la loro origine e l'organizzazione funzionale dei vari
moduli che li compongono.
⌡ 12.1.1 - Multitasking
-----------Abbiamo visto come con l'introduzione del sistema d'interruzione diventa
possibile sviluppare la programmazione concorrente, con cui possiamo pensare
di eseguire 'contemporaneamente' su un processore piu' lavori (task) di uno
stesso utente, saltando da uno all'altro con delle interruzioni software
(chiamate di sistema) inserite nei punti in cui e' opportuno mettere in
'Slip' il task o interruzioni hardware prodotte dai dispositivi di I/O
(tra cui, per esempio, quelle di un real-time clock, prodotte a cadenza
regolare per dividere il tempo della CPU tra i vari task attivi).
Naturalmente occorre mantenere separate le aree di memoria in cui lavorano
i vari task, ma a questo puo' provvedere la tecnica della paginazione:
Interruzioni
+
Paginazione
───────>
(Progr.concorrente)
(MMU, Tab.pagine)
Multitasking
(Multiutenza)
Questo modo di operare puo' essere conveniente sia per dividere la
capacita' elaborativa del processore tra piu' compiti che si vuole
svolgere contemporaneamente, sia per evitare attese al processore,
in corrispondenza di operazioni lente, come quelle di I/O.
Per operare in questo modo (multitasking) basta caricare contemporaneamente, in aree distinte della memoria, il codice eseguibile dei
vari task come processi concorrenti e coordinare, con un programma
supervisore (executive), la condivisione del tempo di elaborazione.
Questo puo' essere fatto in due modi:
1) Multitasking preemptive: e' il caso di un sistema operativo multitasking
in time-sharing (partizioni di tempo), in cui la CPU assegna
il controllo in ogni time-slice ad un task diverso e puo'
interrompere un processo in corso, salvandone lo stato, per
eseguirne uno piu' prioritario (riprendendo poi quello
interrotto da punto in cui era).
2) Multitasking non pre-emptive (cooperativo): in questo caso quando un
processo ottiene il controllo della CPU non puo' piu' essere
interrotto e tiene il controllo finche' non e' terminato.
Gli studenti che hanno seguito gli argomenti trattati nei capitoli precedenti
non dovrebbero avere difficolta' a capire come un tale supervisore potrebbe
essere sviluppato, usando il sistema di interruzione del computer.
Questo e' sufficiente per gli obiettivi del nostro corso, poiche' i dettagli
implementativi di un particolare sistema operativo ci interessano meno, in
quanto il nozionismo diventerebbe prevalente sui concetti di base.
⌡ 12.1.2 - Multiprogrammazione
------------------Un ulteriore passo avanti si avrebbe, se i vari task potessero essere
addirittura programmi di utenti diversi (useremo in questo caso il termine
multiprogrammazione).
La gestione della memoria tramite MMU (Memory Management Unit) in effetti
consente di attribuire pagine diverse ai programmi dei vari utenti, permet-
tendo cosi' di gestire la loro allocazione con un programma supervisore,
attraverso l'uso dei registri della MMU.
Il funzionamento di un sistema del genere sarebbe pero' precario, perche'
un utente sarebbe in grado di compiere azioni che potrebbero compromettere
il funzionamento dei programmi degli altri utenti (per esempio accedendo
alle loro pagine di memoria, dopo aver variato i registri della MMU con le
apposite istruzioni).
L'obiettivo di realizzare un sistema multiprogrammato e' pero' talmente
attraente, che risulta senza'altro conveniente procedere alla costruzione
di processori specificamente dotati di specifici accorgimenti hardware
e software, necessari per impedire che il programma di un utente possa
minacciare l'integrita' degli altri programmi in esecuzione (sia di altri
utenti, che del sistema operativo stesso).
Alcuni di questi accorgimenti da introdurre nel computer sono stati gia'
discussi nel ⌡ 11.5 e sono:
1) Un flip-flop di stato del processore (0/1=Supervisor/User mode). Se il
processore e' in 'User mode' e' impedito l'uso delle istruzioni di
sistema (quelle di I/O, quelle che permettono di modificare le mappe
della MMU e quelle che potrebbero minacciare l'integrita' del sistema
operativo);
2) Un Write-Protect-Bit nelle memorie che permette di leggere ma non di
scrivere nelle memorie;
3) Un Execute-Only-Bit nelle memorie che permette di fare il fetch ma non
di scrivere nelle memorie;
4) Commutazione automatica in Supervisor mode agli interrupts per farli
gestire dal sistema operativo in via esclusiva;
5) Interrupt automatico (trap) se l'utente viola le regole (tentando per
esempio di eseguire istruzioni proibite, come quelle di I/O);
6) Due stack pointers distinti per Supervisor e User mode per poter salvaguardare lo stack del sistema operativo;
7) Utilities di sistema per poter trasferire dati tra utenti diversi (altrimenti reso impossibile dalla MMU, che impedisce mutue interferenze tra
utenti diversi);
8) Inizializzazione automatica al bootstrap del flip-flop di stato e dei
registri della MMU;
9) Istruzioni apposite (system calls) per poter trasferire il controllo al
sistema operativo.
All'utente risulta in genere molto difficile usare direttamente le
chiamate di sistema, sia per carenza di documentazione fornita sia
perche' possono cambiare nelle versioni successive del sistema operativo.
Per risolvere questi problemi vengono fornite delle apposite librerie
(API, Application Programming Interface), che sono ben documentate e
molto piu' stabili nel tempo: sono loro che operano con le chiamate di
sistema, presentando l'uso del servizio in modo standard all'utente.
Si rende cosi' possibile anche il trasporto delle applicazioni da un
sistema operativo ad un altro, come nel caso di Windows NT/2000 e di
Windows 95/98 con le API Win32.
Molte delle chiamate alle procedure API creano oggetti del nucleo
(kernel) del sistema operativo (come file, thread, processi, ecc.).
In tali casi viene restituito dalla chiamata un insieme di parametri
chiamato handle (=maniglia), descrittore dell'oggetto e specifico del
processo che ha creato l'oggetto. Questo handle puo' poi essere usato
dall'utente per eseguire operazioni sull'oggetto, invocando i metodi
dell'oggetto (funzioni API) sulla sua 'handle'.
⌡ 12.2 - Organizzazione funzionale
------------------------La struttura di un sistema operativo puo' essere rappresentata con una
struttura gerarchica, nel senso che ogni livello genera nuove funzionalita'
per i livelli superiori, usando le funzionalita' messe a disposizione dai
livelli inferiori (non di quelli superiori):
Livello 6: Applicazioni dell'utente
Livello 5: Gestione delle applicazioni
Livello 4: Gestione dei flussi dei dati (gestione logica dei files, ecc.)
Livello 3: Gestione periferiche (fornisce periferiche virtuali, risolve i
conflitti di accesso, I/O spooling, ecc.)
Livello 2: Gestione della memoria (fornisce memoria virtuale ai livelli
superiori)
Livello 1: Nucleo del sistema operativo (o supervisor o kernel): gestione
unita' centrale, gestione delle interruzioni, ecc.)
Livello 0: Macchina fisica
Un'altra rappresentazione puo' essere fatta con lo schema seguente:
┌─
│
│
│
│
│
│
│
Sistema │
│
Operativo │
│
│
│
│
│
└─
┌───────────────────────┐
│ APPLICAZIONI UTENTE │
└───────────┬───────────┘
┌───────────┴────────────┐
─┐
│
Shell Comandi
│
│
└───────────┬────────────┘
│
User Mode
┌───────────┴────────────┐
│
│ System Calls I/F (API) │
│
└───────────┬────────────┘
─┘
┌────────────────┴──────────────────┐
─┐
│
I/O HANDLER
SUPERVISOR
│
│
├ ─ ─ ─ ─ ─ ─ ─ ─┬─ ─ ─ ─ ─ ─ ─ ─ ─ ┤
│
│
Spooler
| Gestione Processi│
│
│
File System |
Scheduler
│
│ Supervisor
│
(HD cache)
| IP communication │
│
│
Drivers
| Allocaz.memoria │
│
Mode
└────────────────┬──────────────────┘
│
┌────────────────┴──────────────────┐
│
│NUCLEO (Interrupt service/Priority)│
│
└────────────────┬──────────────────┘
─┘
┌───────────┴──────────┐
│
Macchina Fisica
│
│
( Hardware )
│
└──────────────────────┘
Nei paragrafi seguenti cercheremo di descriverne brevemente i relativi
moduli componenti.
⌡ 12.2.1 - Supervisione
-----------Il compito del modulo supervisore del sistema operativo e' la gestione
della sincronizzazione dei processi (scheduling a breve) e l'uso
dell'hardware, aggiornando delle tabelle di stato delle varie risorse.
Questo viene fatto rispondendo alle chiamate di sistema (system calls,
interruzioni generate da apposite istruzioni), prodotte dalle chiamate
alle funzioni F (primitive di sincronizzazione).
Esempi di funzioni F sono:
LOCK/UNLOCK
SEND/RECEIVE
CREA/ELIMINA PROCESSO
ALLOCA MEMORIA
ecc.
Una funzione F puo' essere eseguita tramite processo o tramite monitor.
L'esecuzione tramite processo avviene nel modo seguente:
Task che invoca la funzione F
=============================
(per esempio F=allocaz.memoria)
................
SEND (Pf,Parametri)
Processo di sistema Pf
======================
System call
-------------> WHILE coda NOT empty DO <-- legge coda
(invocaz.processo
BEGIN
dei messaggi
di sistema Pf)
RECEIVE (mittente,richiesta)
RECEIVE (Pf,risposta)
IF richiesta valida THEN
(attende risposta)
BEGIN
...... ecc. ...... <-----+
esegui richiesta
|
|
|
|
+<------
SEND (mittente,risposta=ok)
END
ELSE
SEND (mittente,risposta=errore)
END.
L'esecuzione tramite programma monitor invece puo' essere rappresentata nel
modo seguente:
Task che invoca la funzione F
=============================
(per esempio F=allocaz.memoria)
................
MONITORCALL (F,Parametri)
..... ecc. .....
Processo di sistema Pf
======================
System call
------------->
(invocaz.funzione
di sistema F)
<--------------
LOCK (Rf)
<-- lock risorsa
modifica MMU di Pf
esegue funzione F
ripristina MMU di Pf
UNLOCK (Rf)
In questo caso il nucleo consente a Pf di accedere a programmi e dati
necessari per eseguire F (in modo protetto).
⌡ 12.2.2 - I/O Spooler
----------In un sistema multiprogrammato non e' possibile concedere agli
utenti di eseguire direttamente operazioni di I/O.
Si pensi per esempio a due programmi di due utenti diversi che si
mettano a stampare contemporaneamente: si avrebbe un mescolamento
delle righe di stampa dell'uno con quelle dell'altro.
La soluzione a questo problema e' semplice: basta assegnare un
diverso file su disco per ogni programma che deve stampare, in
modo che gli output vengano costruiti separatamente su disco.
Si dovra' poi avere uno specifico modulo (spooler) del sistema
operativo, che provveda a scaricare i files sul dispositivo fisico
di output separatamente.
In questo modo i programmi utente possono lavorare come se avessero
ognuno una diversa unita' periferica virtuale in-linea, anche se il
sistema dispone di una sola periferica reale, sulla quale il sistema
di Spool scarica off-line i vari file di output (di qui' il nome di
SPOOL=Simultaneous Peripherals On Line).
La stessa tecnica si usa per l'input. Un pacco di schede, per esempio,
viene letto immediatamente dal sistema di Spool e trascritto in un file
su disco, specifico di un utente. Quando l'applicazione dovra' leggere
i dati, anziche' da schede lo leggera' dal file sul disco. Cosi' ogni
utente vede un suo lettore di schede (virtuale), mentre il sistema
dispone di un solo lettore di schede fisico.
Lo schema di funzionamento della funzione di Spool e' il seguente:
┌─────────┐ ( n utenti )
┌─────────┐
│ PROGR.1 │ ...........
│ PROGR.n │
Applicazioni
└────┬────┘
└────┬────┘
└───────────>─┬─<───────────┘
┌─────────┴──────────┐
│ GESTORE DEI DISCHI │
File system
└─────────┬──────────┘
┌────────────┴─────────────┐
│
DISCO FISICO
│
Unita' fisiche
│Input files
Output files│
└─────┬──────────────┬─────┘
┌───┴───┐
┌───┴───┐
│ INPUT │
│ OUTPUT│ <---- Spooling system
│ SPOOL │
│ SPOOL │
***************
└───┬───┘
└───┬───┘
┌───────┴──────┐ ┌────┴────┐
│LETTORE SCHEDE│ │STAMPANTE│
Unita' fisiche
└──────────────┘ └─────────┘
Il risultato dell'uso di un sistema operativo multiprogrammato puo' quindi
essere rappresentato nello schema seguente:
( 1 utente )
┌────────────────────┐
┌─────────┐ ( n utenti )
┌─────────┐
│ PROGRAMMA UTENTE │
│ PROGR.1 │ ...........
│ PROGR.n │
└─────────┬──────────┘
└────┬────┘
└────┬────┘
┌─────────┴──────────┐ ┌───────────┴─────────┐
┌──────────┴──────────┐
│ Sistema Operativo │ │ Macchina virtuale 1 │.....│ Macchina virtuale n │
│
(Uniprogr.)
│ └──────────┬──────────┘
└──────────┬──────────┘
└─────────┬──────────┘
└───────────>─┬─<───────────┘
┌─────────┴──────────┐
┌─────────┴──────────┐
│ Macchina Fisica
│
│ Sistema Operativo │
│
( Hardware )
│
│
(Multiprogr.)
│
└────────────────────┘
└─────────┬──────────┘
┌─────────┴──────────┐
│ Macchina Fisica
│
│
( Hardware )
│
└────────────────────┘
⌡ 12.2.3 - File system
----------Lo scopo principale del modulo chiamato 'File System' e' di consentire ai
livelli superiori l'accesso logico ai dischi.
La memorizzazione dei dati sui dischi viene fatta da piu' TESTINE di lettura,
ognuna su un diverso piatto magnetico. Su un piatto la registrazione avviene
su piu' TRACCE concentriche, corrispondenti alle varie posizioni del braccio
dove e' montata la testina di lettura. La pista magnetica di una traccia
(circolare su 360 gradi) viene ulteriormente suddivisa in settori, in ognuno
dei quali si puo' memorizzare un blocco di dati.
Quindi su disco non si memorizza un singolo dato, ma un blocco (per esempio
di 512 bytes).
E' possibile cosi' individuare un blocco di dati fornendo al File System
l'indirizzo fisico di TESTINA, TRACCIA e SETTORE, nel modo descritto nel
⌡ 9.6 (sottosistemi a dischi). Poiche', in seguito al susseguirsi di
scritture e cancellazioni, e' possibile che lo spazio rimasto disponibile
su disco sia frammentato, cioe' non in settori contigui nel campo di
indirizzamento, risulta complicato all'utente gestire direttamente l'accesso
al disco.
Il File System risolve questo problema consentendo all'utente di accedere
ai dati su disco, usando nomi i logici dei files anziche' gli indirizzi
fisici e di ritrovare i dati del file, anche se scritto in maniera
frammentata.
Questo viene fatto creando sul disco una directory (come l'indice di un
libro) contenente i nomi logici dei files memorizzati, i loro attributi
ed il link iniziale per accedere alla lista dei blocchi, o cluster, che
compongono il file su disco (un cluster puo' essere costituito da uno o
piu' settori e puo' avere dimensione, per esempio, da 512 a 64K bytes).
Se per la scrittura di un file su disco sono stati usati piu' cluster,
non e' detto che questi risultino contigui su disco. Dobbiamo percio'
usare una struttura dati che ci permetta di recuperare tutti i dati nei
cluster, a partire dal primo, nel giusto ordine.
La struttura idonea allo scopo e' una una lista.
Poiche' si deve anche poter reperire spazio libero per memorizzare nuovi
files e' necessario poter sapere se un cluster su disco e' libero o no.
Per questo bisogna che sul disco ci sia scritta anche una mappa dei
cluster, dalla quale poter dedurre se un cluster e' libero.
Abbiamo da risolvere quindi due problemi: collocare sul disco una mappa di
tutti i cluster ed una tabella contenente i link di ogni file scritto su
disco (lista).
Entrambi i problemi possono essere risolti con un'unica tabella (FAT, File
Allocation Table), come fatto nei PC-IBM, nel modo seguente.
La FAT deve contenere un elemento (2 byte) per ogni cluster del disco:
- se questo elemento e' zero il corrispondente cluster e' libero (e cosi'
abbiamo la mappa del disco);
- se e' diverso da 0 rappresenta il link al prossimo cluster della lista
di un file (convenzionalmente 0FFFH sara' il terminatore della lista,
mentre 0FF7H indichera' un cluster difettoso, non utilizzabile).
Quindi per estrarre dal disco un file con il nome logico DATI, il File
System leggera' la directory e cerchera' il nome DATI; se non c'e' scrive
'FILE NOT FOUND' ed esce; se c'e', ricava il cluster iniziale da cui
avviare la lettura del file; a partire da quel cluster nella FAT trovera'
poi la sequenza di tutti i link con cui leggere, nel giusto ordine, tutti
gli altri cluster del file, fino al link terminatore 0FFFH.
Il processo inverso si fara' nella scrittura, andando a reperire i cluster
liberi nella FAT, scrivendoci i dati del file e registrando nella FAT i
link della lista risultante (con il terminatore finale 0FFFH).
Altri metodi leggermente diversi sono usati nei File System di UNIX o di
Windows NT/2000, ma tutti sono riconducibili alla gestione di una mappa
del disco e delle liste dei blocchi con cui sono stati scritti i files.
Analogia con la gestione delle basi di dati:
------------------------------------------Citiamo, come stimolo di riflessione sulle procedure di gestione dei dati
all'interno di un calcolatore elettronico, l'analogia di funzionamento
tra un File System ed un semplice programma di gestione di dati (esempio
primitivo di database, cioe' di un insieme di dati organizzati e gestiti
da un apposito software DBMS, DataBase Management System).
Possiamo usare la stessa strategia gestionale per organizzare un nostro
archivio. Consideriamo per esempio un archivio di dati, composto dalle
prenotazioni dei posti sui voli di un vettore aereo, che archiviamo su
record diversi di un file ad accesso casuale (random).
Le principali operazioni da compiere per la loro gestione possono essere
programmate in grandi linee nel modo seguente (prevediamo per semplicita'
una sola chiave di ricerca, costituita dal nome del cliente):
- Inserimento di una nuova prenotazione:
1) si legge la mappa e si individua un record libero;
2) si scrive la prenotazione sul record libero;
3) si aggiorna la lista nominativa (legge, aggiorna e riscrive il
relativo file);
4) si riscrive la mappa aggiornata.
- Modifica di una prenotazione:
1) si cerca il nome del cliente fornito dall'operatore nella lista
nominativa (dopo aver letto il relativo file), che e' ordinata
alfabeticamente (vedi il capitolo 2 sulle strutture dei dati);
2) accanto al nome (se lo trova) c'e' il numero di record dove e'
stata scritta la prenotazione (se non lo trova risponde con un
messaggio di errore appropriato);
3) legge il record e presenta i dati all'operatore per la modifica
(editing);
4) dopo la modifica introdotta dall'operatore viene riscritto il record
ed aggiornata la lista nominativa (riscrivendo il file aggiornato)
se e' stato variato il nome del cliente; la mappa non viene variata
perche' il record rimane scritto nella stessa posizione (stesso
numero di record).
- Cancellazione di una prenotazione:
1) si cerca il nome del cliente fornito dall'operatore nella lista
nominativa (dopo aver letto il relativo file);
2) accanto al nome (se lo trova) c'e' il numero di record dove e'
stata scritta la prenotazione (se non lo trova risponde con un
messaggio di errore appropriato);
3) legge il record e presenta i dati all'operatore per la conferma
della cancellazione;
4) se confermata elimina il nome dalla lista nominativa (legge,
modifica e riscrive il relativo file);
5) aggiorna la mappa liberando il record (legge, aggiorna e riscrive
il file della mappa); i dati sul record possono rimanere, tanto
saranno sovrascritti da una prossima memorizzazione perche' nella
mappa il record risulta libero.
E' interessante osservare la seguente corrispondenza:
GESTIONE PRENOTAZIONI
GESTIONE DISCO (FILE SYSTEM)
-----------------------------------------------Mappa dei record liberi
---> FAT
Lista nominativa clienti ---> Directory
File random (contenitore) ---> Area dati su disco
Cio' in quanto in grandi linee sia un file system che un database aiutano
entrambi l'utente alla memorizzazione ed al recupero dei dati su disco.
!----------------------------------------------------------------------CAPITOLO 13 - Sistemi in rete
═══════════
Riassunto: In questo capitolo
una rete locale di
Si parlera' poi di
reti ed i relativi
Internet.
viene spiegato come e' possibile realizzare
computer, sia sul piano hardware che software.
reti geografiche e si descriveranno le interprotocolli, con particolare riferimento ad
⌡ 13.1 - RETI LOCALI
----------Fino agli anni '70 la connessione di computer, a parte l'uso dei front-end,
connessi ai mainframe nei centri di calcolo per l'organizzazione dell'I/O
e pochi progetti pilota, era limitata essenzialmente alle esigenze del
trasferimento di files.
Con l'avvento dei primi personal computer, alla fine degli anni '70, si
comincio' a concepire una rete locale di PC, composta da piu' personal
computer collegati tra loro via cavo e confinati in un'area limitata,
tipicamente l'edificio di un'azienda, come un sistema 'general purpose'
in grado di gestire applicazioni in multiutenza, in concorrenza ai sistemi
multiprogrammati (composti da un computer con piu' terminali) usati fino
ad allora.
Il successo di quest'idea fu reso possibile dal basso costo dei personal
computer e dalla maggiore affidabilita' di funzionamento raggiungibile con
piu' unita' di elaborazione.
Le prime reti, basate sull'architettura client-server, dedicavano un computer
(server) alla gestione della base-dati su disco ed alla condivisione delle
funzioni di output. Infatti per un'applicazione multiutente in cui piu'
utenti possono eseguire operazioni concorrenti sulla stessa base-dati, e'
opportuno detenere un unico archivio dei dati su un computer che ne assicuri
la condivisione degli accessi. La stessa esigenza di condivisione si
manifesta quando si vuole consentire a tutti gli utenti l'uso una stessa
stampante, per esempio per ragioni di economicita'.
L'architettura client-server, tuttora molto usata soprattutto nell'uso di
basi-dati, prevede che il server manipoli i dati su richiesta del client e
che invii al client richiedente solo le poche informazioni relative al
risultato dell'elaborazione (e non tutti i dati dei files necessari per far
compiere l'elaborazione al client). Si ottiene cosi' una notevole riduzione
della quantita' di dati trasferiti sulla rete.
La soluzione adottata fu fin dall'inizio quella ovvia di programmare un
computer con un apposito programma 'server', capace di soddisfare le
richieste degli altri computer ad esso collegati, che (grazie ad un'apposita
programmazione 'client') sottoponevano via cavo richieste di accesso ai dati
su disco e di stampa.
Trattandosi di applicazioni con condivisione di dati e di output, era
necessario realizzare i necessari accorgimenti, come semafori e spool
dell'I/O.
Oggi le reti si stanno sviluppando sempre di piu' come elemento strutturale
e strategico delle economie mondiali perche' offrono la possibilita' di
estendere la potenzialita' di elaborazione oltre i limiti imposti sul singolo
calcolatore elettronico dalla velocita' della luce che, imponendo limiti
fisici alla propagazione dei segnali elettronici all'interno dei calcolatori,
ne limita di fatto le massime prestazioni raggiungibili.
L'ulteriore vantaggio delle reti e' cosi' quello di permettere una maggiore
potenzialita' elaborativa tramite lo sfruttamento dell'elaborazione parallela
e distribuita in tutte le diverse applicazioni che gli utenti devono gestire
contemporaneamente.
Seguendo il nostro solito approccio didattico di spiegare i principi di funzionamento con gli esempi piu' semplici possibili, cominciamo a descrivere
la prima rete di questo tipo che realizzammo nel 1980 in Italia sui personal
computer allora disponibili (gli Apple II, dotati di 48K RAM e 143K su floppy
disk: gli hard disk per PC ancora non erano disponibili).
Questa rete, non pubblicata in letteratura, non e' solo un esercizio per
la didattica, ma e' stata effettivamente utilizzata per alcuni anni nella
realizzazione di sistemi di elaborazione in multiutenza in aziende
commerciali e turistico/alberghiere italiane, fino all'avvento delle prime
reti locali basate su PC-IBM. Per l'esiguita' delle risorse richieste (pochi
kilobytes di memoria e nessuna scheda di rete), potrebbe addirittura essere
usata anche oggi in sistemi integrati a controllo automatico distribuito
con microprocessori a 8 bit.
Con questa semplice rete spiegheremo, evitando per ora le complessita'
delle reti attuali, non essenziali ai nostri fini, quali nuovi elementi
bisogna introdurre per realizzare un rete locale:
1) Elementi hardware: cavo e schede di rete;
2) Elementi software: driver per la scheda di rete e software di rete
nelle due versioni Client e Server;
3) Modalita' di sincronizzazione e comunicazione: protocolli.
Potremo anche capire funzionalita' avanzate come la programmazione della
elaborazione distribuita ovvero la possibilita' di inviare, per esempio,
da un computer Client un comando ad un altro computer Server per pilotare
l'esecuzione di programmi su di esso residenti.
⌡ 13.2 - COLLEGAMENTO IN RETE
-------------------Per realizzare la connessione tra i computer nella rete, chiamata MicroNet,
occorsero i seguenti elementi:
1) Hardware: il supporto fisico della comunicazione era costituito in questo
caso da un cavo a tre fili e dalle interfacce seriali (che svolgevano il
ruolo che oggi viene svolto dalle schede di rete) ai due capi del
collegamento tra i computer Client e Server (collegamento punto-punto):
TX
┌──────┐──────────────────>┌──────┐
│Client│───── Ground────── │Server│
└──────┘<───────────────── └──────┘
RX
2) Driver (software): l'Apple II non era dotato di UART, ma gestiva la
comunicazione seriale asincrona con un apposito loop software, che
alzava od abbassava il livello sulla linea di trasmissione (o leggeva
lo stato della linea in ricezione) con la cadenza stabilita dal baudrate, che era di 19200 bit/sec.
E' stato possibile quindi, programmando con poche istruzioni Assembly
il processore Rockwell 9502 (8 bit e 1MHz, equivalente ad un Motorola
6800), usare le due linee RX e TX anche in modo non standard RS232,
semplicemente come linee di stato alto/basso per attivare le funzioni
di controllo, come la 'Richiesta' di servizio (Look-At-Me) usata in
modalita' polling dai computer Client o la 'Risposta' del computer
Server, quando si mette in ricezione del comando trasmesso dal Client.
Essendo il Server dedicato, cioe' non assolveva altre funzioni oltre
quella di rispondere alle richieste dei client, lo si e' programmato
con un polling continuo sullo stato delle linee seriali ad esso
collegate (una per ogni computer Client).
Il driver era costituito da una piccola routine (poche decine di
istruzioni assembly), presente nei due computer, con la quale:
- uno trasmetteva un blocco di 256 bytes presenti in una pagina di
memoria (buffer) dove il programma aveva scritto i dati;
- l'altro riceveva nella sua pagina di buffer, dove il programma li
andava a leggere dopo la ricezione.
3) Protocollo: e' l'insieme delle regole comuni con cui i computer
comunicanti gestiscono la comunicazione (chi riceve deve acquisire
i dati con la stessa sequenza, con cui l'altro computer li sta
trasmettendo), prevedeva vari formati dei comandi possibili.
Un pacchetto scambiato poteva avere un formato del tipo:
┌────┬────┬────┬────┬────┬────┬────┬────┐
│Funzione │ .....Dati....... │CheckSum │
└────┴────┴────┴────┴────┴────┴────┴────┘
Come esempio elenchiamo alcuni comandi richiesti dal Client al Server
con la relativa sequenza di dati scambiati (il protocollo non prevedeva
soltanto il pacchetto iniziale di comando, ma anche gli eventuali altri
scambi successivi, necessari al completamento del comando):
A) Lettura file sequenziale sul disco del Server:
---------------------------------------------Passo 1: Client alza livello di richiesta sulla linea seriale TX
Passo 2: Server risponde alzando l'altra linea RX e si mette in
ricezione seriale quando TX si abbassa (=procedura di
connessione).
Passo 3: Client trasmette il pacchetto di comando con
Funzione=Lettura file sequenziale (1 byte)
Dati=Nome del file
e poi si mette in ricezione seriale a 19200 baud su RX.
Passo 4: Server riceve il pacchetto, riconosce la funzione da eseguire
ed avvia la routine appropriata, leggendo il file sul proprio
disco; al termine inizia a trasmettere i dati a 19200 baud
sulla linea RX, in blocchi di lunghezza prefissata
┌────┬────┬────┬────┬────┬────┐
│ .....Dati.....
│CheckSum │
└────┴────┴────┴────┴────┴────┘
Passo 5: Client riceve il pacchetto dei dati e li inserisce nel buffer,
come se provenissero dal proprio hard disk (cosi' i programmi
scritti in linguaggi di alto livello procederanno senza
accorgersi che i dati sono stati letti dalla rete).
La ricezione di tutti i pacchetti procede in rapida successione e solo alla fine il client trasmette al server il
messaggio di acknowledgement o di errore (scelta fatta
perche' la trasmissione risulta molto affidabile).
Passo 6: Server dopo la trasmissione dell'ultimo pacchetto si mette in
ricezione sull'altra linea del messaggio di acknowledgement o
di errore inviato dal client: in caso di errore si ripete il
ciclo di trasmissione altrimenti il comando e' terminato.
B) Scrittura file sequenziale sul disco del server:
----------------------------------------------Il protocollo e' del tutto analogo a quello della lettura.
Anche per lettura/scrittura di record di file random si procede in
modo analogo, con l'apposita funzione ed aggiungendo al nome del
file il numero del record (la lunghezza dei record e' gia' nota al
server).
C) Stampa:
------Due sono i modi possibili:
- Inviando un pacchetto di dati corrispondente ad una singola riga di
stampa (senza processo di spool):
┌────┬────┬────┬────┬────┬────┬────┬────┐
│F=Stampa │ .....Dati.....
│CheckSum │
└────┴────┴────┴────┴────┴────┴────┴────┘
- Inviando un pacchetto con il comando di avvio in stampa di dati che
il server legge sui suoi dischi: in questo caso si inserisce nel
server la programmazione necessaria a svolgere questo compito (come
si fa oggi per esempio con i servlet sui server Web).
Per ogni routine attivabile dal client sul server veniva inviato
un pacchetto di comando con apposito codice funzione ed i dati
necessari all'espletamento del comando. Per esempio nell'applicazione
in questione erano predisposti dai client sul server tanti ordini
(commerciali) che al completamento venivano fatturati con un solo
comando che identificava la funzione da svolgere (fatturazione) e
forniva come dati il codice del cliente (con cui il server poteva
individuare l'ordine su disco).
Il vantaggio di questa procedura e' evidente: con l'invio di un
semplice comando si avviava una procedura complessa, che comportava
numerose registrazioni sui dischi del server e sulla stampante.
Questa procedura, pilotata direttamente dal server, poteva procedere
alla massima velocita' senza problemi di concorrenza da parte degli
altri computer client e senza bisogno di un sistema di spooling, che
in sistemi senza hard disk risulterebbe problematico.
Con questi esempi si puo' capire bene cosa si intende con il termine di
protocollo: le regole comuni (realizzate nel 'software di protocollo')
che i due computer comunicanti devono rispettare per potersi scambiare
comandi ed informazioni in modo sincronizzato, ben al di la del singolo
pacchetto scambiato.
⌡ 13.3 - SOFTWARE DI RETE
---------------Rimane ora da capire come si possono progettare i due componenti del
software di rete, che chiameremo ClientWare e ServerWare per non fare
confusione con Client e Server (con cui abbiamo indicato i computer).
OBIETTIVO: La funzionalita'
consentire ad un utente che
di accedere ad un hard disk
la stessa facilita' con cui
realizzata dal software di rete deve
programma in un linguaggio ad alto livello
o ad una stampante del computer Server con
accede al disco o stampante locale.
STRATEGIA: Poiche' l'utente programma in un linguaggio ad alto livello,
questo accede ai dischi con una chiamata di sistema, che puo' essere
intercettata, modificando il relativo vettore d'interruzione, con una
procedura analoga a quella seguita dagli hacker per compiere un'infezione
virale: il nuovo vettore dell'interruzione puntera' alla routine
'Quale drive?' (vedi figura), che inviera' le chiamate dirette al drive C:
sull'indirizzo del driver locale (il vettore d'interruzione originale) e
dirottera' invece sul software di rete (quello indicato con tratti doppi
nello schema) le chiamate dirette al drive condiviso sul server (E:
nell'esempio).
SOLUZIONE: Il software di rete, mostrato con un doppio trattino nel
diagramma seguente, gestisce le operazioni come nella precedente
descrizione del protocollo:
┌───────────────────┐
│Chiamata di sistema│
└──────────┬────────┘ COMPUTER CLIENT
│
---------------
COMPUTER SERVER
(Vettore interruz.)
--------------║
╔══════╩═════╗ ClientWare
ServerWare
║Quale drive?║ ╔═══════╗
╔═══════╗
┌────────┐
║ C: ║ E: ╠══╣NetWare║ Software di ║NetWare╠═══════┤ Server │
╚══╦═══╩═════╝ ╚═══╦═══╝ protocollo ╚═══╦═══╝
└───┬────┘
│
║
(in comune)
║
│
┌──────┴───────┐
╔════╩════╗
╔════╩════╗
┌──────┴───────┐
│Driver lettura│
║Driver SK╠═----------═╣Driver SK║
│Driver lettura│
└──────┬───────┘
╚═════════╝
Cavo
╚═════════╝
└──────┬───────┘
┌──────┴───────┐
┌──────┴───────┐
│ disco locale │
(I componenti del software di rete
│ disco server │
└──────────────┘
sono quelli a tratto doppio)
└──────────────┘
Nello schema di funzionamento, che anche nei software di rete usati oggi
ha la stessa impostazione, occorrono quindi i seguenti elementi:
1) Una coppia di programmi ClientWare e ServerWare (chiamati per esempio
da Microsoft: Client per reti e Condivisore di risorse);
2) Una coppia di schede di rete con relativi programmi driver;
3) Un software di protocollo, che puo' essere diverso per i vari tipi di
reti (Microsoft, Novell, ecc.).
I moderni sistemi operativi (OS) inglobano il software di rete. Si parla
allora di SISTEMI OPERATIVI DI RETE (NOS, Network Operating System), come
Netware della Novell o Windows NT.
Nelle reti Microsoft presenti nel nostro laboratorio questi componenti si
possono vedere e selezionare nella finestra Rete del Pannello di controllo,
che si apre cliccando su Risorse del sistema.
⌡ 13.3.1 - PROTOCOLLI DI COMUNICAZIONE
--------------------------Il protocollo di comunicazione e' l'insieme delle regole scelte per lo
scambio dei messaggi (formato dei pacchetti di dati e significato dei
campi) e trova relizzazione pratica nel software di protocollo.
Le applicazioni non interagiscono direttamente con l'hardware della rete,
ma usano come interfaccia il software di protocollo, che implementa le
regole del protocollo usato.
I protocolli di interesse per il nostro corso sono:
NetBEUI (NetBios Enhanced User Interface): E' il protocollo di rete
sviluppato da IBM e Microsoft come implementazione dello standard
NetBIOS (Network Basic I/O System, l'interfaccia API che fornisce
i servizi per la gestione di reti locali LAN).
NetBEUI fornisce i servizi di trasporto per piccole reti locali
(fino a 200 computer), che gestiscono le comunicazioni tra i vari
computer tramite il software NetBIOS.
E' un protocollo semplice e veloce, ma non e' istradabile tra reti
diverse (attraverso i router), a differenza di TCP/IP.
Quest'ultimo pero', essendo piu' ricco di funzionalita', ha un
maggiore sovraccarico (overhead) sul sistema e puo' quindi
risultare troppo gravoso per alcuni sistemi o applicazioni.
E' usato nella rete locale del laboratorio delle esercitazioni
pratiche.
TCP/IP : E' il pacchetto di protocolli piu' usato. Fornisce capacita' di
istradamento e supporto per molte piattaforme e servizi come SNMP
(Simple Network Management Protocol, il protocollo standard di
Internet per il controllo ed amministrazione remota della rete),
DHCP (Dynamic Host Configuration Protocol, permette ai computer di
ottenere gli indirizzi IP dal server DHCP), WINS (Windows Internet
Name Service), DNS (Domain Name Service), ecc.
⌡ 13.4 - INTERCONNESSIONE DELLE RETI
--------------------------Le reti esistenti sono diverse, realizzate con tecnologie che le rendono
tra loro incompatibili. Esiste pero' un metodo (internetworking), basato
sia su componenti software che su dispositivi fisici, che permette comunque
di interconnettere tra loro reti diverse, fino a realizzare cosi' un
servizio universale (Internet, la rete delle reti), attraverso l'uso di
reti eterogenee.
⌡ 13.4.1 - DISPOSITIVI DI CONNESSIONE
-------------------------I dispositivi fisici usati per le interconnessioni sono diversi a secondo
del tipo di servizio richiesto:
1) Ripetitori e/o amplificatori di segnale: si usano nelle connessioni su
distanze lunghe (per esempio oltre 150 metri) per eliminare i problemi
dovuti all'attenuazione dei segnali. Possono anche consentire la
connessione di segmenti diversi di cavo (anche con supporto fisico
diverso, per esempio coassiale BNC o twisted-pair RJ45), purche' il
protocollo di accesso sia lo stesso.
2) HUB: e' un dispositivo che realizza il nodo centrale di collegamento
di una rete con topologia di connessione a stella. Se sono attivi
(alimentati) fungono anche da ripetitori, se sono intelligenti possono
fornire servizi (istradamento, packet switching, ecc.). Nella rete
locale del laboratorio di esercitazione si puo' vedere un esempio di
uso di un Hub attivo.
3) BRIDGE (ponte): e' un ripetitore intelligente, usato nella segmentazione
delle reti per connettere i diversi segmenti tra loro. Permette di
ridurre la congestione sul segmento dov'e' connesso, perche' riceve le
trasmissioni dei pacchetti di dati dagli altri segmenti, ne interpreta
l'indirizzo di destinazione (con un'apposita tabella di 'bridging') e,
se non sono destinati al suo segmento, li ritrasmette, evitando che
lo attraversino (cioe' permette di 'saltare' il segmento in cui si trova,
funzionando da 'ponte' per il traffico dei pacchetti di dati).
I bridge consentono di connettere segmenti con diversi supporti fisici
(per esempio coassiale BNC o twisted-pair RJ45). Esistono anche i bridge
traduttori che consentono di connettere reti con schemi di accesso
diversi al supporto fisico (per esempio Token ring e Ethernet).
4) ROUTER (istradatore): e' un dispositivo di connessione superiore al
bridge perche' e' in grado di effettuare scelte intelligenti sul
percorso e sul filtraggio dei pacchetti in transito, al fine di
ottenere il massimo throughput (velocita' di flusso) dei dati.
L'istradamento viene determinato usando l'indirizzo della rete
anziche' del computer destinatario (cioe' il router lavora ad un
livello superiore dell'architettura di rete rispetto al bridge),
usando una tabella d'istradamento. Questa tabella puo' essere
statica (variata solo dall'amministratore) o dinamica, nel qual
caso un apposito software verifica la disponibilita' ed efficienza
dei percorsi possibili e mantiene costantemente ottimizzata la
tabella d'istradamento (comunicandola anche agli altri router).
Il router puo' essere un computer dedicato o un normale computer
della rete, dotato di una tabella d'istradamento e collegato mediante
piu' schede di rete ai diversi segmenti della rete, tra i quali deve
svolgere la funzione di istradatore.
Dato che il router lavora ad un livello superiore dell'architettura
di rete rispetto al bridge, puo' connettere reti eterogenee funzionanti
con protocolli diversi, purche' istradabili. Sono istradabili quei
protocolli che possono indirizzare pacchetti dati a segmenti di rete
diversi da quello a cui appartengono, come TCP/IP o IPX/SPX (non e'
invece istradabile NETBEUI, che puo' indirizzare solo i computer della
sua LAN).
5) BROUTER (Bridge+Router): e' un dispositivo capace di funzionare da
bridge, se il pacchetto ricevuto ha un protocollo non istradabile, o
da router se invece il pacchetto ricevuto ha un protocollo istradabile.
Ovviamente per svolgere questi compiti ha bisogno di entrambe le
tabelle, di bridging e d'istradamento.
6) GATEWAY: e' un dispositivo che svolge il lavoro di traduzione necessario
per consentire la connessione di segmenti di rete eterogenei o di
computer diversi nella stessa LAN (per esempio PC-IBM, Macintosh e
Mainframe). Svolge anche la funzione di traduzione dei protocolli, per
cui puo' ricevere un messaggio IPX/SPX e trasmetterlo in TCP/IP al
destinatario che opera con questo diverso protocollo.
Essendo le funzionalita' svolte dal software, questi dispositivi possono
trovare realizzazione pratica in computer dedicati (in genere meno costosi
di un PC) o in un normale computer della rete, dotato di quanto occorre
per eseguire la funzionalita' voluta in multitasking.
⌡ 13.4.2 -
INTER-RETI
---------Nel seguito ci interesseremo dell'interconnessione di reti diverse con il
protocollo TCP/IP, per realizzare un servizio universale (Internet, la rete
delle reti), sia pure attraverso l'uso di reti eterogenee.
I dispositivi fisici che useremo per ottenere cio' sono dei particolari
computer (router), dedicati a raccordare fisicamente le diverse reti,
convertendo i protocolli ed instradando il traffico verso altri router,
fino alla rete di destinazione finale.
I componenti software, residenti su ogni computer dell'inter-rete,
realizzano l'universalita' del servizio (attraverso i protocolli TCP/IP),
dando all'utente l'impressione di operare su un'unica rete omogenea.
In generale quindi una inter-rete e' un insieme di reti diverse collegate
tra loro tramite dei router, al fine di realizzare una rete virtuale unica
ed omogenea.
I computer delle differenti reti,indipendentemente dalla loro dimensione,
quando sono collegati all'inter-rete, sono detti 'host'. Essi comunicano
tra loro tramite i software di protocollo, residenti su tutti gli host e
router, che assolvono il compito di nascondere i dettagli fisici delle
sottoreti e di simulare l'esistenza di un unica rete omogenea (inter-rete),
trasportando i pacchetti di dati attraverso i router fino all'host di
destinazione.
L'inter-rete e' quindi un'astrazione resa possibile dal software dei
protocolli.
⌡ 13.4.3 - PROTOCOLLI TCP/IP
----------------La prima famiglia dei protocolli sviluppati per inter-reti (TCP/IP) e'
ancora la piu' usata. Essa e' strutturata in 5 livelli.
SOFTWARE DI PROTOCOLLO: Livelli dell'interfacciamento
=====================================================
┌─────────────────────────────────────────┐
│ I/F con le applicazioni (HTTP, FTP,...) │ <--- Livello 5 APPLICAZIONE
├─────────────────────────────────────────┤
│
Trasporto (TCP)
│ <--- Livello 4
TRASPORTO
├─────────────────────────────────────────┤
│
Indirizzamento Inter-rete (IP)
│ <--- Livello 3
INTER-RETE
├─────────────────────────────────────────┤
│ Interfaccia di rete (Software di rete) │ <--- Livello 2
├─────────────────────────────────────────┤
│ Interfaccia con l'hardware (Driver)
│ <--- Livello 1
└─────────────────────────────────────────┘
RETE
FISICO
Il livello 1 (Fisico) si occupa dei dispositivi fisici della rete (driver).
Il livello 2 (Rete) si occupa di organizzare e trasmettere i dati in
pacchetti su una singola rete.
Nel livello 3 (Inter-rete) ci sono i protocolli che si occupano del formato
dei pacchetti per l'inoltro dal mittente al destinatario nell'inter-rete,
ovvero attraverso i router da rete a rete.
Il livello 4 (Trasporto) si occupa dell'affidabilita' della comunicazione
nell'inter-rete (TCP).
Nel livello 5 (Applicazione) ci sono i protocolli specifici delle applicazioni, quelli cioe' che specificano come una certa applicazione usa
l'inter-rete (HTTP, FTP,...).
⌡ 13.4.4 - INDIRIZZAMENTO IP (INTERNET PROTOCOL)
------------------------------------Per poter simulare un sistema inter-rete omogeneo e' necessario avere
un unico schema di indirizzamento nella comunicazione, in cui ad ogni
stazione (punto di collegamento per host o router) corrisponde un unico
indirizzo, indipendentemente dagli indirizzamenti usati sulle singole
reti, che possono anche essere incompatibili.
Nei protocolli TCP/IP viene usato lo schema di indirizzamento IP (Internet
Protocol), in cui un indirizzo e' formato da un numero di 32 bit.
Un indirizzo IP non identifica uno specifico computer ma uno specifico
collegamento tra computer e sottorete (stazione o port).
Se un computer ha piu' collegamenti deve avere un indirizzo IP per ogni
collegamento: e' il caso dei router, che collegano sottoreti diverse, o
degli host multi-homed, in cui si attiva piu' di un collegamento per
migliorare l'affidabilita' o le prestazioni.
Ogni pacchetto di dati inviato sull'inter-rete contiene i due indirizzi
IP: quelli della stazione mittente e di quella destinataria.
L'indirizzo IP, per comodita' degli utenti, viene rappresentato in forma
decimale puntata (per esempio: 191.9.25.3), in cui i 4 byte (4x8=32 bit)
sono scritti come interi in base 10, separati da un punto.
Per maggiore comodita' e' stata anche introdotta la possibilita' di usare
dei nomi simbolici, che vengono tradotti automaticamente nell'indirizzo
binario IP da un apposito software.
Ciascun indirizzo IP e' composto da due parti: il prefisso ed il suffisso.
Il prefisso identifica la rete fisica dell'host, mentre il suffisso e'
l'identificativo unico dell'host in quella rete (pero' host di sottoreti
diverse possono avere lo stesso suffisso).
Le lunghezze in bit di prefisso e suffisso determinano il numero massimo
di reti ed il numero massimo di stazioni (host e router) all'interno di
una sottorete.
Per ridurre la rigidita' conseguente ad un'attribuzione unica del numero
di bit ai due campi, si e' deciso di definire cinque classi di indirizzi
(in base ai bit 0..3). Nelle prime tre (classi primarie A, B e C) sono
attribuite lunghezze diverse per prefisso e suffisso, permettendo cosi'
di ottenere la maggiore elasticita' voluta per il massimo numero di reti
ed il massimo numero di stazioni all'interno di una sottorete:
bit
Classe A
Classe B
Classe C
0 1 .......7 8
16
24
31 Primo byte
┌─┬──────────┬─────────┬──────────┬─────────┐
│0│ Prefisso │
Suffisso
│
0...127
└─┴──────────┴─────────┴──────────┴─────────┘
┌─┬─┬────────┬─────────┬─────────┬──────────┐
│1│0│
Prefisso
│
Suffisso
│ 128...191
└─┴─┴────────┴─────────┴─────────┴──────────┘
┌─┬─┬─┬──────┬─────────┬─────────┬──────────┐
│1│1│0│
Prefisso
│ Suffisso │ 192...223
└─┴─┴─┴──────┴─────────┴─────────┴──────────┘
Classe
A
B
C
Bits prefisso
7
14
21
N.max sottoreti
128
16384
2097152
Bits suffisso
24
16
8
N.max staz./rete
16777216
65536
256
Altre due classi sono state riservate per gli indirizzi multicast (nella
trasmissione broadcast l'indirizzo del ricevente, di classe D, viene
condiviso tra piu' host che ricevono cosi' contemporaneamente uno stesso
pacchetto) e per usi futuri:
bit
Classe D
Classe E
0 1 .......7 8
16
24
31 Primo byte
┌─┬─┬─┬─┬────┬─────────┬─────────┬──────────┐
│1│1│1│0│
Indirizzo multicast
│ 224...239
└─┴─┴─┴─┴────┴─────────┴─────────┴──────────┘
┌─┬─┬─┬─┬────┬─────────┬─────────┬──────────┐
│1│1│1│1│
Riservato per usi futuri
│ 240...255
└─┴─┴─┴─┴────┴─────────┴─────────┴──────────┘
Nell'inter-rete quindi ogni sottorete ha un unico identificativo (network
number, prefisso) ed ogni host della sottorete ha un unico identificativo
diverso all'interno della sottorete (suffisso).
Nell'inter-rete questi indirizzi svolgono lo stesso ruolo che gli indirizzi
fisici svolgono nelle singole reti: una stazione mittente, che deve inviare
un pacchetto di dati, mette l'indirizzo IP della stazione destinataria nel
giusto campo del pacchetto e lo passa al software di protocollo che provvede
ad inoltrarlo. Il software di protocollo istallato nella rete di destinazione
provvedera' a farlo arrivare al giusto indirizzo 'fisico' della particolare
rete destinataria (diverso dall'indirizzo di protocollo).
Per poter collegare una rete ad Internet occorre ottenere l'attribuzione
di un numero di rete dalla societa' di telecomunicazione (Internet Service
Provider) che assicura la connettivita' su rete pubblica.
Per garantire l'univocita' dei prefissi, queste societa' si coordinano con
un'organizzazione centrale (IANA = Internet Assigned Number Authority).
Nelle inter-reti private invece l'attribuzione dei prefissi spetta al
proprietario.
Gli indirizzi seguenti sono definiti come 'riservati' e non possono quindi
essere attribuiti ad alcuna stazione:
Prefisso
Suffisso
Tipo indirizzo
Funzione
--------------------------------------------------------------------Tutti 0
Tutti 0
'Questo host'
Usato all'avvio
Rete X
Tutti 0
Rete
Identifica la rete X
Rete X
Tutti 1
Broadcast orientato Broadcast a rete X
Tutti 1
Tutti 1
Broadcast ristretto Broadcast su rete locale
127
Qualunque
Loopback
Per test applicazioni
Il prefisso 127 e' molto utile nelle esercitazioni perche' permette di
simulare il collegamento in rete, cioe' di provare i programmi applicativi
senza doverli istallare su due host diversi (basta usare per esempio
l'indirizzo di loopback 127.0.0.1).
Esempio di attribuzione di indirizzi IP (alle sottoreti ed ai router) in
un'inter-rete con tre sottoreti diverse, collegate attraverso due router:
╔══════════════════════╗
║ Ethernet 135.108.0.0 ║
Sottorete di classe B
╚══════════╦═══════════╝
│
│ ┌────────┐
135.108.99.5 ──> └─┤ Router ├─┐ <── 213.240.129.2
└────────┘ │
│
╔═════════════╩════════════╗
║ Token Ring 213.240.129.0 ║ Sottorete di classe C
╚═════════════╦════════════╝
│
│ ┌────────┐
213.240.129.12 ──> └─┤ Router ├─┐ <── 75.0.0.15
└────────┘ │
│
╔═══════╩══════╗
║ WAN 75.0.0.0 ║ Sottorete di classe A
╚══════════════╝
E' possibile aumentare il numero dei router, rendendo la topologia di
interconnessione ridondante, per migliorare l'affidabilita' o le
prestazioni.
Il software di protocollo contenuto nei router decide il successivo
percorso che un pacchetto (datagramma) deve compiere, in base ad una
tabella d'istradamento in esso memorizzata.
Nel datagramma compare solo l'indirizzo IP della destinazione finale
(non quello del successivo percorso).
I router determinano quindi il percorso lungo l'inter-rete (istradamento).
Inoltre, per propagare il datagramma attraverso le differenti sottoreti
fisiche, i router provvedono ad inserire il datagramma in un frame ammesso
alla trasmissione nei dispositivi di ogni sottorete attraversata
(incapsulamento).
Ognuna di queste sottoreti ha un limite alla dimensione massima del frame
(MTU, Maximum Transmission Unit). Se un datagramma supera questa dimensione
massima MTU, stabilita dalle specifiche delle sottoreti, il router che
lo deve istradare lo divide in frammenti piu' piccoli (frammentazione),
che vengono trasmessi indipendentemente lungo l'inter-rete, fino alla
destinazione finale, dove vengono ricomposti per ricostruire il datagramma
originario.
La versione attuale del protocollo IP (versione 4) funziona molto bene, ma
si prevede che risultera' presto insufficiente lo spazio d'indirizzamento
a 32 bit. Per questo la IETF ha progettato la versione 6 (IPv6) con
indirizzi a 128 bit.
⌡ 13.4.5 - INDIRIZZAMENTO SU INTERNET
-------------------------Il protocollo di comunicazione usato in Internet e' TCP/IP (Transmission
Control Protocol /Internet Prococol).
Il primo protocollo (TCP) organizza i dati in pacchetti di lunghezza
fissa e controlla che siano trasmessi bene (packet switching).
Ogni pacchetto ha un suo indirizzo di origine e destinazione e viene
inviato con istradamento in rete sul percorso piu' conveniente (PPP,
Point to Point Protocol, e' l'implementazione su linea telefonica
(seriale) del protocollo TCP/IP).
L'indirizzo IP (di un computer) viene assegnato dall'IR (Internet Registry)
ad ogni rete che chiede di connettersi ad Internet ed e' un numero di 32
bit, usualmente indicato in 4 bytes con notazione 'dotted decimal'.
Esempio:
C025410AH = 192.37.65.10 (in esadecimale C0.25.41.0A)
( 192=Nazione; 37=Ditta; 65=Sede; 10=Computer )
E' possibile far corrispondere ad ogni indirizzo IP un nome simbolico
(piu' pratico per l'utente), composto da una sequenza di segmenti
alfanumerici separati da punti:
Hostname.Subdomain.ToplevelDomain
Per ottenere un nome di dominio occorre registrarsi presso l'ente
Internet preposto, che attribuisce un suffisso di dominio univoco.
Se una ditta ha registrato il suo nome di dominio come 'ditta.it'
i suoi host possono avere nomi del tipo:
computer1.ditta.it
dove:
computer1=Nome host; ditta.it=nome del dominio
Se la stessa ditta ha sedi a Roma e Milano, puo' introdurre un
ulteriore livello nella gerarchia per individuare la sede, usando
nomi del tipo:
computer.sede.ditta.it
e se ogni sede ha piu' uffici, un altro livello gerarchico puo' servire
a specificarli:
computer.ufficio.sede.ditta.it
L'ordine gerarchico risulta cosi' inverso a quello degli indirizzi
numerici IP.
Il sistema dei nomi di dominio (DNS) lascia completa liberta' all'utente
di scegliere numero e significato dei segmenti alfanumerici nel nome di
dominio, salvo il segmento piu' significativo, che deve rispettare le
assegnazioni seguenti:
com
Societa' commerciale
edu
Istituzione accademica
gov
Ente statale
mil
Ente militare
net
Gestore servizi di rete
org
Organizzazione diversa
int
Organizzazione internazionale
arpa
Dominio temporaneo ARPA
sigla nazione
Le stringhe usabili (domini e sottodomini) sono illimitate, senza
distinzione tra maiuscole e minuscole.
Questa notazione simbolica si chiama FQDN (Full Qualified Domain Name).
La traduzione in indirizzo IP e' fatta da un'applicazione di data-base
distribuito (residente su piu' computer della rete) chiamata DNS (Domain
Name Server): un'applicazione richiede la traduzione al suo server DNS,
che risponde con l'indirizzo IP. Se il server non e' in grado di eseguire
direttamente la traduzione diventa a sua volta client di un altro server
DNS, e cosi' via fino a quando la traduzione non e' eseguita (data-base
distribuito). I piccoli utenti non hanno bisogno di istallare il software
DNS perche' possono avvalersi di quello sul server dell'Internet Service
Provider, che fornisce loro la connettivita' in rete.
I nomi NETBIOS (Microsoft) dei computer in rete nel nostro laboratorio
(es. USER1) sono lunghi fino a 15 caratteri.
I servizi di traduzione degli indirizzi dei computer NETBIOS-->IP,
necessari nelle reti che usano il protocollo TCP/IP (Transmission Control
Protocol / Internet Protocol) sono residenti su server WINS o DNS, che
ricevono la richiesta di traduzione e restituiscono l'indirizzo IP al
client.
L'indirizzo IP del server di traduzione degli indirizzi puo' essere
impostato dall'operatore del client o assegnato automaticamente dal
server Web (la scelta si fa nella finestra delle Impostazioni del
protocollo TCP/IP):
WINS (Window-Internet Name Service)=Servizio di traduz.del Nome NETBIOS
del computer nell'indirizzo IP
Esempio:
Computer Client -----> USER1 -------> Server WINS
<--- 121.19.2.1 <--DNS (Domain Name Service) = Servizio di traduzione del Nome NETBIOS del
computer nell'indirizzo IP
Esempio:
Computer Client -----> USER1.AZIENDA.COM -------> Server DNS
<------- 121.19.2.1 <--------Il servizio di traduzione degli indirizzi dei computer, anziche' essere
centralizzato su un server in rete, puo' essere distribuito sui clients
gestendo localmente i files LMHOST e HOST
⌡ 13.4.6 - PROTOCOLLO IP: DATAGRAMMI ED ISTRADAMENTO
----------------------------------------Il principale servizio di TCP/IP e' il trasporto e la consegna dei
pacchetti di dati, senza connessione diretta tra le stazioni trasmittente
e ricevente.
Questi pacchetti (datagrammi IP) sono un formato standard (virtuale),
che viene tradotto dal software di protocollo TCP/IP presente in tutte le
sottoreti nei formati (reali), riconosciuti dai vari dispositivi delle reti
fisiche (non omogenee), che formano l'inter-rete.
Un datagramma IP e' composto dal blocco dei dati, preceduto da una
intestazione contenente gli indirizzi IP di mittente e destinatario, oltre
ad altre informazioni come lunghezza, tipo di dati, checksum, ecc.
La lunghezza del datagramma e' stabilita dall'applicazione e puo' arrivare
fino a 64K bytes.
Per disturbi nella trasmissione attraverso le reti fisiche e' possibile che
alcuni datagrammi IP vengano persi, alterati, duplicati o consegnati in
ritardo (quindi in ordine diverso da quello di spedizione).
Il software del protocollo IP non si occupa della soluzione di questi
problemi, ma lascia questo compito alle applicazioni che usano IP per
comunicare.
Per la soluzione di questi problemi si rendono disponibili, ad un livello
piu' alto della famiglia TCP/IP, i servizi piu' affidabili, orientati alla
connessione, come il protocollo di trasporto TCP e ad un livello ancora
superiore (perche' usa TCP) il protocollo HTTP per trasporto di ipertesti.
La famiglia TCP/IP comprende anche un protocollo per il controllo e la
notifica degli errori verificatisi nella trasmissione, chiamato ICMP
(Internet Control Message Protocol). Questi due protocolli convivono
sempre insieme nel senso che IP usa ICMP per notificare il verificarsi di
anomalie e ICMP usa IP per trasmettere le notifiche degli errori.
Il servizio di IP senza connessione e' un esempio di trasmissione in
commutazione di pacchetto (packet switching): con questa tecnica un
messaggio lungo puo' essere scomposto in piu' pacchetti (datagrammi
IP), ognuno dei quali viene trasmesso indipendentemente da un router
ad un altro, lungo l'inter-rete, usando le informazioni contenute
nell'intestazione (indirizzo del destinatario), finche' l'ultimo router
non lo consegna alla stazione di destinazione.
Ciascun router dispone di un software, che usa una tabella d'istradamento
con la quale, quando riceve un datagramma, puo' ricavare dall'indirizzo
IP di destinazione, a quale prossimo indirizzo inoltrare il datagramma
(quello di un altro router o della stazione destinataria, se si trova
nella sottorete direttamente accessibile).
La tabella d'istradamento viene caricata nel router all'avvio ed aggiormata
ad ogni variazione dei collegamenti nella rete.
Poiche' il router trasmette il datagramma ad altri router, per eseguire
questo istradamento non gli occorre l'indirizzo completo della stazione
destinataria, ma solo il prefisso ovvero l'indirizzo della sottorete in
cui si trova la stazione di destinazione (cio' poiche' ogni router
corrisponde all'interfaccia di accesso ad una sottorete).
Questo consente di contenere la dimensione della tabella d'istradamento,
che dovra' contenere tutte le coppie:
Indirizzo della sottorete destinataria ---> Prossimo indirizzo a cui
(e non di tutti gli host indirizzabili)
trasmettere il datagramma
Il software del router puo' ricavare l'indirizzo della sottorete di
destinazione dall'indirizzo IP della stazione destinataria, presente nel
datagramma, grazie alla maschera dell'indirizzo (address mask), contenuta
nella tabella d'istradamento.
Questa maschera specifica quali bit dell'indirizzo IP compongono il
prefisso della sottorete (quelli corrispondenti ai bit 1 della maschera).
Per esempio il router A dell'inter-rete seguente:
╔══════════════════════╗
║ Ethernet 131.108.0.0 ║
Sottorete di classe B
╚══════════╦═══════════╝
│
│ ┌────────┐
131.108.99.5 ──> └─┤Router A├─┐ <── 223.240.129.2
└────────┘ │
│
╔═════════════╩════════════╗
║ Token Ring 223.240.129.0 ║ Sottorete di classe C
╚═════════════╦════════════╝
│
│ ┌────────┐
223.240.129.17 ──> └─┤Router B├─┐ <── 78.0.0.17
└────────┘ │
│
╔═══════╩══════╗
║ WAN 78.0.0.0 ║ Sottorete di classe A
╚═══════╦══════╝
│
│ ┌────────┐
78.0.0.18 ──> └─┤Router C├─┐ <── 95.0.0.30
└────────┘ │
│
╔═══════╩══════╗
Sottorete di classe A
║ WAN 95.0.0.0 ║
╚══════════════╝
potrebbe avere una tabella di istradamento come quella sotto riportata
(eventuali destinazioni non elencate avrebbero un'istradamento d'ufficio
prestabilito):
ESEMPIO DI TABELLA D'ISTRADAMENTO PER IL ROUTER A
------------------------------------------------------Sottorete dest.
Mask bits
Indirizzo d'invio
------------------------------------------------------78. 0. 0. 0
255. 0. 0. 0
223.240.129. 17
95. 0. 0. 0
255. 0. 0. 0
78. 0. 0. 18
131.108. 0. 0
255.255. 0. 0
Consegna all'host
223.240.129. 0
255.255.255. 0
Consegna all'host
------------------------------------------------------in base alla quale i datagrammi contenenti gli indirizzi di destinazione
indicati nella prima colonna della tabella seguente, per esempio, vengono
inoltrati agli indirizzi riportati nell'ultima colonna:
DATAGRAMMA IP |
TABELLA D'ISTRADAMENTO NEL ROUTER A
----------------+----------------------------------------------------Indirizzo IP
| Sottorete dest.
Mask bits
Indirizzo d'invio
----------------+----------------------------------------------------131.108. 25.105 | 131.108. 0. 0
255.255.0.0
Consegna all'host
223.240.129.12 | 223.240.129. 0
255.255.255.0
Consegna all'host
78.112.225.65 |
78. 0. 0. 0
255.0.0.0
223.240.129. 17
95.224.131.16 |
95. 0. 0. 0
255.0.0.0
78. 0. 0. 18
----------------+----------------------------------------------------PROCEDURA D'ISTRADAMENTO ESEGUITA DAL SOFTWARE DEL ROUTER:
All'arrivo di un datagramma il software del router deve estrarre l'indirizzo
IP di destinazione e poi per ogni riga della tabella d'istradamento deve:
1) applicare la maschera all'indirizzo (AND);
2) confrontare l'indirizzo della sottorete di destinazione cosi' ricavato
con quello presente nella riga della tabella d'istradamento;
3) se uguale inoltrare il datagramma all'indirizzo riportato sulla stessa
riga e terminare;
4) se diverso passare alla riga successiva della tabella d'istradamento,
ripartendo dal punto 1;
5) se si arriva al termine della tabella senza trovare la sottorete di
destinazione nella tabella, inoltrare il datagramma all'indirizzo del
router prestabilito d'ufficio.
Anche i router B e C dell'inter-rete considerata nell'esempio precedente
avranno tabelle analoghe a quella del router A, che permettono al software
dei router di determinare i percorsi per tutti i possibili indirizzi IP
presenti nell'inter-rete.
⌡ 13.4.7 - PROTOCOLLO DI CONTROLLO DELLA TRASMISSIONE (TCP)
-----------------------------------------------E' il piu' importante protocollo di trasporto della famiglia TCP/IP a
disposizione delle applicazioni.
Con TCP/IP due applicazioni su computer diversi A e B possono instaurare
una connessione, scambiarsi messaggi in modo full-duplex ed affidabile e
chiudere la connessione al termine (connessione punto-punto).
TCP usa IP per il trasporto dei dati, incapsulando i suoi messaggi nei
datagrammi IP. Quando IP ha recapitato un datagramma, ne passa il contenuto
a TCP senza interpretarlo.
Il software TCP dev'essere quindi nei computer tra i quali si instaura la
connessione, ma non nei router, come mostrato nello schema seguente (in cui
la parte tratteggiata indica il sistema di comunicazione IP usato da TCP):
COMPUTER A
COMPUTER B
┌──────────────┐
┌──────────────┐
│ Applicazione │
│ Applicazione │
├──────────────┤
├──────────────┤
│
TCP
│
Sistema di comunicazione IP
│
TCP
│
+--├═─═─═─═─═─═─═─┤---------------------------------├═─═─═─═─═─═─═─┤--+
| │
IP
│
ROUTER
│
IP
│ |
| ├──────────────┤
┌──────────────┐
├──────────────┤ |
| │ I/F di rete │
│
IP
│
│ I/F di rete │ |
| └──────┬───────┘
├──────────────┤
└───────┬──────┘ |
|
│
│ I/F di rete │
│
|
|
│
└───┬──────┬───┘
│
|
|
│
╔════════╗
│
│
╔════════╗
│
|
|
└─────╣ RETE 1 ╠──────┘
└──────╣ RETE 2 ╠─────┘
|
|
╚════════╝
╚════════╝
|
+----------------------------------------------------------------------+
Esempio di connessione TCP con ritrasmissione di un messaggio (handshake):
COMPUTER A
══════════
Trasmette messaggio 1
Riceve acknowledge 1
────────────────>
<────────────────
COMPUTER B
══════════
Riceve messaggio 1
Trasmette acknowledge 1
Trasmette messaggio 2
Riceve acknowledge 2
────────────────>
<────────────────
Riceve messaggio 2
Trasmette acknowledge 2
Trasmette messaggio 3
. . . . . . . . .
Scade tempo di attesa
──>...Pacchetto perso...
Ritrasmette messaggio 3 ────────────────>
Riceve acknowledge 3
<────────────────
ecc.
Riceve messaggio 3
Trasmette acknowledge 3
Il protocollo TCP e' orientato alla connessione, ovvero le applicazioni
devono esplicitamente stabilire una connessione prima di comunicare,
richiedendone l'apertura prima e la chiusura poi.
Per alcune applicazioni e' piu' conveniente risparmiare il tempo di
apertura della connessione anche a scapito dell'affidabilita' nel recapito
del messaggio. Per questi casi il protocollo TCP mette a disposizione il
protocollo UDP (User Datagram Protocol) per comunicazioni senza connessione
(il datagramma viene spedito senza alcun controllo sul buon esito della
ricezione).
⌡ 13.5 - ARCHITETTURA CLIENT-SERVER
-------------------------L'inserimento nel computer dei componenti di rete fornisce la possibilita'
di accesso alle risorse di altri computer anche distanti.
Questo apre la strada allo sviluppo delle tecnologie di comunicazione e di
elaborazione sia in rete locale che geografica, che vengono indicate oggi
con il termine High-Tech.
Distinguiamo due scenari applicativi:
1) Reti in cui e' prevalente la comunicazione e la distribuzione delle
informazioni (World Wide Web, Intranet aziendali, ecc.).
2) Reti in cui e' prevalente l'elaborazione dei dati (Reti locali,
Intranet/Extranet, ecc.);
Nel primo caso vengono situate su files e directories di un computer
server varie informazioni (testi, immagini, suoni, ecc.), che devono
essere rese disponibili secondo le regole stabilite ai vari computer
clientcollegati alla rete. Quest'idea, nata al CERN nel '90 per
distribuire documenti tra i gruppi di ricerca, ha dato origine al
World Wide Web ed al successo di Internet.
La presentazione di informazioni multimediali con uso di ipertesti
(contenenti 'link' ad altri elementi informativi rappresentabili) ha
portato a progettare in modo particolare i due programmi client e
server che devono gestire questo modo di distribuire ai client le
informazioni residenti sui server.
Sono cosi' nati i programmi Web-Server, come Apache o IIS (Internet
Information Server), ed i browser, come Netscape Navigator o Internet
Explorer, capaci di interrogare con opportuni protocolli di comunicazione
il server, interpretando il testo ricevuto in linguaggio HTML (HypetText
Markup Language).
L'uso sia dei Browser che del Web server Apache, descritto in un'apposito
file nel dischetto delle dispense, fa parte del programma delle
esercitazioni pratiche.
Nel secondo caso si puo' realizzare un sistema di elaborazione
multi-utente facendo elaborare i vari computer 'client' sugli stessi
dati residenti sui dischi di un computer 'server' (controllando
correttamente la concorrenza con semafori messi anch'essi in files
condivisi sul server). In alcuni casi pero' la quantita' di dati da
trasferire dal server al client per eseguire un compito (per esempio
una ricerca) puo' essere troppo grande per la capacita' di trasmissione
della rete.
In questi casi puo' essere piu' conveniente lanciare dal client il
comando di eseguire il compito al server, che potra' eseguire
l'elaborazione piu' efficientemente, potendo accedere direttamente
ai dati residenti sui suoi dischi. Il server invia poi al client
solo i risultati dell'elaborazione, evitando cosi' i problemi di
trasmissione di molti dati sulla rete.
Possiamo cosi' distinguere tre possibilita' per la cosiddetta
architettura software delle applicazioni in rete:
1) Centralizzata: L'applicazione e' tutta sul server ed i client lo
interrogano (Database, programmazione ad oggetti con istanze in
memorie diverse)
2) Condivisione di file: L'applicazione e' sui client e usa files
condivisi su uno o piu' server
3) Client/Server: L'applicazione e' distribuita su client e server
(caso ibrido)
In quest'ultimo modo di funzionamento, architettura Client-Server,
il computer Server non solo gestisce le richieste di accesso alle
sue risorse (dischi, stampanti, modem, ecc.) da parte dei computer
Client, ma esegue anche dei comandi, come per esempio quelli relativi
alle interrogazioni di un database, come nel caso dei Server SQL
(=Structured Query Language, un linguaggio standard per database
relazionali).
Il funzionamento di Internet e' basato su:
- Protocollo di comunicazione TCP/IP
- Metodo di indirizzamento degli host
- Architettura Client/Server
La concorrenza (multitasking) e' essenziale, poiche' il server puo'
attivare un nuovo thread (o processo o task) di controllo per ciascuna
richiesta da servire, cosicche' piu' client possano essere serviti
contemporaneamente.
Nell'architettura client/server i client accludono a ciascuna richiesta
inviata un numero identificatore (=porta) del servizio richiesto; il
software del server ricevente puo' allora stabilire a quale thread
inoltrare la richiesta.
⌡ 13.5.1 - COMUNICAZIONE IN RETE TRA APPLICAZIONI (INTERFACCIA SOCKET)
----------------------------------------------------------Client e server comunicano tramite il protocollo di trasporto, che puo'
essere orientato alla connessione o privo di connessione (UDP).
Nel primo caso le applicazioni devono instaurare una connessione prima
di poter comunicare.
Nel secondo caso invece l'applicazione non deve accertare, prima dello
invio di un messaggio, la disponibilita' del destinatario a riceverlo,
ma puo' trasmettere verso qualunque destinazione in qualunque momento.
Per fare questo le applicazioni devono interagire con il protocollo di
trasporto (TCP).
Questo puo' avvenire utilizzando l'interfaccia API (Application Program
Interface), che consiste in un insieme di procedure che le applicazioni
possono richiamare.
Molti costruttori hanno adottato l'interfaccia API 'socket', che si e'
cosi' imposta come standard di mercato.
Una procedura API in genere corrisponde ad un'operazione fondamentale,
come per esempio l'apertura di una connessione o la trasmissione di
un messaggio. Trattandosi di operazioni standard, le peculiarita'
dell'aggancio con le applicazioni scritte su una particolare piattaforma
sono curate dal sistema operativo. Nella versione Unix BSD l'interfaccia
socket fa parte del sistema operativo (cosi' e' stata creata a Berkeley).
In altri sistemi operativi le socket sono aggiunte come libreria di
procedure (socket library).
L'uso delle socket per la comunicazione attraverso il protocollo di
trasporto (I/O in rete) segue le stesse modalita' di accesso ai file
sequenziali:
open - read - write - close
La chiamata alla procedura 'open' (=creazione di una socket) restituisce
indietro un numero intero descrittore della socket, che verra' usato come
argomento nelle successive chiamate alle procedure read, write e close
(senza bisogno di specificare ogni volta l'indirizzo del destinatario).
Rispetto all'I/O su file sequenziale, alla 'open' bisogna passare piu'
parametri: il protocollo di trasporto, l'indirizzo del destinatario, il
tipo dell'applicazione (client o server).
Esempi:
1) La procedura 'socket' crea una socket e restituisce il descrittore:
descrittore = socket (fam_prot, tipo, protocollo)
2) La procedura 'close' ('closesocket' in Windows) chiude la socket:
close (socket)
(socket=descrittore)
3) La procedura che associa un numero di porta del protocollo alla socket:
bind (socket, ind_locale, lungh_ind)
4) La procedura che definisce una socket come passiva (di un server):
listen (socket, lungh_coda)
5) La procedura che accetta la prossima richiesta di connessione (server):
nuova_sock = accept (socket, ind_client, lungh_ind_client)
6) La procedura che permette ad un client di connetersi ad un server:
connect (socket, ind_server, lungh_ind_server)
E cosi' via con le procedure per trasmettere e ricevere: send, sendto,
sendmsg, recv, recvfrom, recvmsg, ecc.
Il modo in cui si realizza la comunicazione tra due applicazioni, usando
l'interfaccia socket, e' descritto nell'esempio seguente (tra parentesi
sono indicate le procedure da usare per creare un servizio, in cui un
server invia un messaggio ad un client che richiede una connessione):
Applicazione sul server
----------------------Server crea una socket
(socket)
Le associa un N. di porta (bind)
Rende la porta passiva
(listen)
Accetta una connessione (accept)
Invia il messaggio
(send)
Chiude la connessione
(close)
Applicazione sul client
----------------------Client crea una socket (socket)
Si collega al server
Riceve dati in arrivo
Chiude la connessione
(connect)
(recv)
(close)
Un esempio di programmazione pratica in C di questo esempio e' riportata
nel Cap.25 del libro di D.Comer.
Altri esempi di programmazione in Java si trovano nel tutorial sul sito
della SUN:
http://java.sun.com/docs/books/tutorial/networking/sockets/readingWriting.htm
l
Nelle esercitazioni di laboratorio verra' mostrato l'uso dei Socket nella
realizzazione pratica di un server Web in Java.
La comunicazione nella programmazione in architettura Client-Server puo'
essere gestita anche e piu' facilmente attraverso i servlets, che sono
programmi Java, analoghi alle applet, che vengono eseguiti all'interno
del Web server (abilitato a Java).
Si puo' dire, per analogia, che i servlet stanno al Web Server, come le
applet stanno al browser.
Grazie alla programmazione Java essi offrono un modo alternativo, piu'
facile ed efficiente degli script CGI per estendere le funzionalita' del
server (ad esempio per generare documenti dinamici, per gestire data-base
aiendali, ecc.), in modo indipendente dalla piattaforma.
Documentazione ed esempi si trovano nel tutorial sul sito della SUN:
http://java.sun.com/docs/books/tutorial/networking/servlets/index.html
Un Servlet Tutorial con esempi si puo' trovare sul sito della Unify:
www.NewAtlanta.com/ServletExec AS/Documentation/servlet_tutorial.html
Riportiamo qui un esempio di semplice server HTTP realizzato in Java,
usato nell'esempio di commercio elettronico nelle esercitazioni (il
codice Java sara' comprensibile allora, dopo lo studio del linguaggio).
Esso e' in grado di ricevere la richiesta inoltrata da un browser (con
un ServerSocket nel main che attiva il thread run), prelevare dal
proprio hard-disk la pagina HTML richiesta (con il thread run) ed
inviarla al browser (con il metodo invioPagina).
Spiegazioni piu' dettagliate saranno possibili durante l'esercitazione
pratica.
/*
======= Esempio di server HTTP multithread con uso di Socket =========
*
* Questo esempio, tratto dal programma di ricerca RUN condotto dal gruppo
* di Calcolatori Elettronici, mostra come si realizza in Java un server
* HTTP. Esso e' stato descritto in un apposito seminario, tenuto dal
* dott.F.Baldasseroni nel nostro Laboratorio ed e' dedicato alla
* programmazione in rete di applicazioni in architettura client-server.
* Questo server puo' essere interrogato da un browser (client) e risponde
* nel giusto formato (MIME), come farebbe un Web server Apache, IIS, ecc.
* In questo esempio restituisce il file richiesto in HTTP dal browser.
*/
import java.net.*;
import java.io.*;
import java.util.*;
public class httpServer extends Thread
{ static int Porta=4444;
static boolean debug=false;
static String nomeHost, errorPage;
String filRequested;
Socket theConnection;
// -------------- Metodo main --------------public static void main (String[] args)
{ if (args.length == 0) { debug=false; }
else { debug=true;
System.out.println ("Esecuzione in modalita' debug");
}
errorPage = "<html><body><h1>Documento non trovato!</h1><p><a
href='index.html'>torna alla pagina iniziale</a><p></body></html>";
ServerSocket ss; // Dichiara ss come variabile ServerSocket
try
{ ss = new ServerSocket(Porta); // <--- Attiva il ServerSocket ss, in
ascolto sulla Porta=4444
System.out.println ("Server RUN in ascolto sulla porta :" +
ss.getLocalPort());
// Consente gestione di piu' Client sulla stessa Porta (multithread)
while (true)
{ httpServer ts = new httpServer (ss.accept()); // Accetta una
nuova connessione ts sul Socket ss
ts.start(); // Crea il thread per rispondere al Client
}
}
catch (IOException e) { System.out.println("error 1: " + e); } //
Gestione errori
} // fine main
// -------- Metodo httpServer, con segnatura (Socket s) --------// Definisce il Socket theConnection = Connessione stabilita sul Socket s
public httpServer (Socket s)
{ theConnection = s; }
/* ---------- Metodo run -----------Thread lanciato dal serverSocket per gestire le singole connessioni http
(simile a routine di servizio d'interruzione, ma ad un livello superiore)
*/
public void run()
{ try {
PrintWriter os = new PrintWriter (theConnection.getOutputStream(),
true);
System.out.println ("connessione attivata con " + theConnection);
BufferedReader is = new BufferedReader (new InputStreamReader
(theConnection.getInputStream()));
System.out.println ("dati ricevuti dal client:");
String request = is.readLine();
System.out.println (request);
if (request.indexOf("HTTP/")!=-1)
{ if (request.indexOf("GET /")!=-1)
{ int st, en;
st = en = -1;
st = request.indexOf("GET /") + 5;
if (request.indexOf("html")!=-1) {
en=request.indexOf("html") + 4; }
else if (request.indexOf("htm")!=-1) {
en=request.indexOf("htm") + 3; }
else {
// Spazio disponibile per gestire richieste differenti da .html e .htm, per
es. l'invio di un'immagine o di un applet
}
if (debug) { System.out.println ( "start target: " + st +
" - " + "end target: "+ en ); }
try { if (debug) { System.out.println ( "page:*"+
request.substring(st,en) + "*" ); }
filRequested = request.substring(st,en);
}
catch (StringIndexOutOfBoundsException e)
{ System.out.println ("errore parsing richiesta: " +
e.toString());
errorResp (os);
}
} // end if
while (true)
{ String thisLine = is.readLine();
System.out.println (thisLine);
if (thisLine.trim().equals("")) break;
}
File flIn = new File (filRequested);
System.out.println ("invio intestazioni MIME al client..");
//
INIZIO INVIO INTESTAZIONE MIME + dati
if (!flIn.exists())
{ long lenTxt = errorPage.length();
Date now = new Date();
os.print ("HTTP/1.0 404 File not found\r\n");
os.print ("Date: " + now + "\r\n");
os.print ("Server: RUNServer 1.0\r\n");
os.print ("Content-length: " + lenTxt + "\r\n");
os.print ("Content-type: text/html\r\n\r\n");
errorResp (os);
}
else
{ long lenTxt = flIn.length();
Date now = new Date();
os.print ("HTTP/1.0 200 Ok\r\n");
os.print ("Date: " + now + "\r\n");
os.print ("Server: RUNServer 1.0\r\n");
os.print ("Content-length: " + lenTxt + "\r\n");
os.print ("Content-type: text/html\r\n\r\n");
invioPagina (os,filRequested, debug);
} // TERMINE INVIO INTESTAZIONE MIME + dati
} //end if
} // end try
catch (IOException e) { System.out.println("error 2: " + e); }
} // end run
// ------------ Metodo invioPagina -----------private void invioPagina (PrintWriter os, String pageRequested, boolean
deb) throws IOException
{ FileInputStream fis = new FileInputStream (pageRequested);
DataInputStream dis = new DataInputStream (fis);
byte[] fisImage = new byte[dis.available()];
dis.readFully (fisImage);
dis.close();
String pagina = new String (fisImage);
if (pagina.indexOf ("Ora attuale")!=-1)
{ String pagina1 = pagina.substring (0,pagina.indexOf("Ora
attuale")+ "Ora attuale".length()+1 );
String pagina2 = pagina.substring (pagina.indexOf("Ora attuale")+
"Ora attuale".length()+ 1, pagina.length() );
pagina = pagina1 + " " + new Date() + pagina2;
}
if (deb) { System.out.println (pagina); }
os.println (pagina);
dis.close ();
theConnection.close ();
} // end invioPagina
// -------- Metodo errorResp --------private void errorResp (PrintWriter os) throws IOException
{ os.println (errorPage);
theConnection.close();
}
} // end class httpServer
⌡ 13.5.2 IL PROTOCOLLO HTTP
-----------------HTTP (HyperText Transfer Protocol) e' un protocollo, usabile a livello
applicazione, per gestire sul server le risorse ipertestuali. Con esso
client e server si scambiano messaggi contenenti anche 'meta-informazioni'
in un formato simile al MIME (Multipurpose Internet Mail Extensions),
usato per la posta elettronica multimediale.
Normalmente la comunicazione HTTP usa una connessione TCP/IP (su default
port=80, se non diversamente specificato nell'URL).
Esempio di URL su porta 80:
"http://www.microsoft.com:80/index.html"
La comunicazione tra client e server avviene in modalita' handshake:
- Connessione (su TCP/IP port 80 o altro non riservato, specificato in URL)
- Richiesta (messaggio inviato dal client)
- Risposta (inviata dal server al client)
- Close (chiusura della connessione fatta dal client o dal server)
La richiesta contiene l'identificatore dell'oggetto richiesto, il
comando (metodo) da applicare all'oggetto ed altre informazioni nel
formato seguente (vedi www.w3.org/Protocols/HTTP/Request.html,
CR+LF = Carriage Return + Line Feed = Terminatore di riga):
Request
=
Simple o Full
Simple
=
GET <URI> CR+LF
Full
=
Metodo URI ProtocolVersion CR+LF
[*<HTRQ Header>]
[<CR+LF><Messaggio>]
Metodo
=
Vers.Protoc.=
URI
=
<Header>
=
<Messaggio> =
<Comando>
HTTP/1.0 (stabilisce il formato seguente)
Identificatore (URL o URN)
<FieldName> : <Value> <CR+LF>
Oggetto, conforme al formato MIME
(Multipurpose Internet Mail Extensions)
Con l'identificatore URI indichiamo l'indirizzo URL (Uniform Resource
Locator, che e' una stringa contenente il tipo di connessione necessario,
l'indirizzo dell'host, il numero di porta opzionale ed il percorso del
file richiesto) o il nome URN (Uniform Resource Name), per i server che
risolvono gli URN
Alcuni dei metodi possibili sono:
GET
:
HEAD
:
PUT
:
POST
:
DELETE
ecc.
:
:
Scarica dal server i dati indirizzati
dall'identificatore URI. Se questo indirizza
un processo o uno script eseguibile viene
scaricato l'output del processo e non il
codice del processo o script.
Come GET ma scarica solo l'Header senza il
Messaggio
Scrive il messaggio (oggetto) nell'URL
specificato (che dev'essere gia' esistente)
Idem, creando l'URL (come impostato dal
client o assegnato dal server)
Cancella sia l'oggetto che l'URL inviato
...........
COMMERCIO ELETTRONICO
--------------------Come esempio di programmazione distribuita su Internet in protocollo HTTP,
viene presentata durante le lezioni un'applicazione di commercio elettronico
che funziona nel modo seguente (gli indirizzi sono quelli del test delle
esercitazioni):
1) Un cliente scarica dal sito di E.commerce la pagina index.html,
http://localhost:4063/index.html
nella quale con un form sceglie tra le opzioni acquistabili quella
voluta e preme il button submit per lanciare l'ordine al servlet 'buyer'
indicato nel campo 'action' del form
2) Il server riceve l'ordine (HTTP), avvia il servlet 'buyer' che verifica
la correttezza dell'ordine, lo inserisce nel database (file acquisti.dat)
e trasmette la conferma d'ordine come pagina HTML al client
3) Il magazziniere, con il browser di un computer client, indirizza il
servlet apposito ('ordini') per evadere gli ordini
http://localhost:4063/servlets/ordini
che elimina l'ordine evaso dal database degli ordini da evadere e invia
un'e.mail al cliente
Tutti i codici risiedono nel sito che e' sul dischetto delle esercitazioni
nella directory <ecom>.
Si noti che, nel caso di un vero commercio elettronico in rete, tutta
l'applicazione sarebbe istallata solo sul server.
Sui client si potrebbero anche eseguire elaborazioni distribuite con
le applet Java, scaricate di volta in volta dalla rete e quindi senza
alcuna istallazione sui computer dei clienti (rete Extranet).
L'esempio mostrato e' di commercio elettronico perche' stimola la curiosita'
dello studente, essendo una delle tecnologie alla base della "new economy".
Il tipo di elaborazione mostrata nell'esempio in realta' e' piu' generale
di quanto non possa sembrare a prima vista, poiche' permette ad un utente
(client) di lanciare richieste di elaborazione su un database allo stesso
computer (server), dove il database risiede.
Nell'ambiente dei fisici e' questa un'esigenza molto ricorrente, che puo'
essere gestita con metodologie simili a quella vista ora con riferimento
al commercio elettronico.
Proteggendo adeguatamente gli accessi al server con certificati e firme
digitali, magari crittografando anche i messaggi, e' possibile realizzare
reti Intranet, in cui eseguire applicazioni di elaborazione distribuita
e/o parallela a disposizione dei ricercatori dell'esperimento di fisica.
Java permette cosi' lo sviluppo di elaborazioni distribuite tra server
(con i servlet) e client (con le applet), dove applet e servlet possono
comunicare tra loro anche usando l'interfaccia Socket.
⌡ 13.5.3 - POSTA ELETTRONICA
----------------Una delle applicazioni client-server piu' usate quella che realizza il
servizio di posta elettronica, il cui uso e' ormai ben noto:
- il mittente, con il suo software 'client' di posta elettronica
(E-mail), contatta un computer con il software server di posta
elettronica, richiedendo una connessione TCP;
- appena la connessione e' instaurata le due applicazioni usano il
protocollo SMTP (Simple Mail Transfer Protocol), con il quale il
client si qualifica, indica il destinatario e invia il messaggio.
Il messaggio puo' anche contenere informazioni di natura diversa
dal testo ASCII, se il mittente include nell'intestazione una riga
che indica l'uso dello standard MIME (Multipurpose Internet Mail
Extensions) e nel corpo del messaggio le informazioni aggiuntive
che permettono ai destinatari di interpretare il contenuto.
Gli indirizzi di posta elettronica hanno il formato mailbox@computer
dove:
- 'computer' permette al software del computer mittente di identificare
il computer destinatario;
- 'mailbox' permette al software del server destinatario di individuare
la casella postale, a cui corrisponde uno spazio sul disco.
Un indirizzo E-mail, oltre che ad una casella postale, puo' anche
corrispondere ad un programma. In tal caso il messaggio viene recapitato
al programma indirizzato (per esempio un'interrogazione di un database),
il quale lo elabora e rispedisce al mittente la risposta, sempre via
E-mail.
Per permettere l'accesso remoto alle caselle postali del server, questo
deve avere costantemente attiva una speciale applicazione (server POP
per accesso remoto), che risponde alle chiamate telefoniche dei computer
client e, una volta accertatane l'identita' (richiedendo user_name e
password), consente loro di instaurare la connessione.
Per accedere alla casella postale viene usato in questo caso il POP
(Post Office Protocol), che e' un protocollo della famiglia TCP/IP.
⌡ 13.5.4 - TRASFERIMENTO DI FILES (FTP)
---------------------------La famiglia TCP/IP mette a disposizione due protocolli per eseguire
il trasferimento di files tra due computer: uno piu' completo (FTP,
File Transfer Protocol) e l'altro invece ridotto all'essenziale (TFTP,
Trivial File Transfer Protocol).
Il servizio viene svolto da due applicazioni che funzionano secondo
il modello client-server.
Con il protocollo TFTP la comunicazione avviene attraverso connessioni
UDP, mentre con FTP si usano connessioni TCP.
L'utente che vuole eseguire un'applicazione FTP client, deve instaurare
una connessione di controllo con l'FTP server, autenticando la propria
identita' con login e password (e' anche possibile creare un account
'anonymous', quando si vuole consentire l'accesso ad utenti non
registrati). La connessione di controllo rimane attiva finche' non
viene eseguito esplicitamente il comando di chiusura.
Attraverso la connessione di controllo si inviano i comandi, mentre per
il trasferimento dei dati si usa una seconda connessione dedicata, con
numero di porta diverso, che viene chiusa automaticamente al termine
del trasferimento.
La comunicazione FTP lungo la connessione puo' essere automatica (batch),
come nel caso delle applicazioni di posta elettronica (interfaccia MIME
per il trasferimento di informazioni multimediali) o interattiva. In
questo caso un apposito interprete di comandi permette all'utente di
eseguire, sia sul computer client che sul server, comandi standard del
file system come: visualizzare files e cartelle sul client o sul server,
trasferire files in formato testo o binario, ecc.
I comandi dell'utente vengono prima interpretati dal client FTP.
Se sono comandi locali vengono eseguiti senza comunicare con il server,
altrimenti il client compone la richiesta di servizio al server e gliela
invia secondo il protocollo FTP. Il server riceve, riconosce ed esegue
il comando, rispondendo con lo stesso protocollo.
Il servizio TFTP (FTP banale) funziona invece solo in modalita' batch,
consente il solo trasferimento di file tramite UDP (quindi non instaura
una connessione TCP) e non prevede ne' login ne' password (i files
trasferibili risultano di dominio pubblico).
⌡ 13.5.5 - FILE SYSTEM DI RETE (NFS)
------------------------Oltre ai servizi di trasferimento dei files tra computer, la famiglia
dei protocolli TCP/IP mette a disposizione anche NFS (Network File
System, sviluppato da Sun e diventato ormai uno standard de-facto).
Si tratta di una ulteriore funzionalita' di accesso diretto ai files
di un computer remoto, che permette alle applicazioni su un client
NFS di leggere, modificare o copiare porzioni di file, permettendo
anche la loro condivisione in rete.
Questa funzionalita' NFS, che consente l'accesso diretto ai file di
rete attraverso TCP/IP, viene integrata nel file system del sistema
operativo del computer (non e' un'applicazione come FTP).
In questo modo con NFS un'applicazione dell'utente puo' manipolare
direttamente anche files non locali: per esempio, per modificare una
piccola porzione di un grande file remoto, il client NFS intercetta il
comando al disco (chiamata di sistema), lo interpreta e se riconosce
che il file indirizzato e' remoto (non locale) invia dati e comando di
scrittura al server NFS, dove e' residente il file; questo esegue la
scrittura ed invia indietro al client la risposta di conferma della
corretta esecuzione del comando. In questo modo NFS funge da tramite
per eseguire il comando sul computer remoto, in modo trasparente alla
applicazione. Si evita cosi' il trasferimento del grande file: in rete
vengono trasmessi solo i pochi dati da scrivere.
La condivisione dei files in rete e' anche resa possibile, richiedendo
l'accesso esclusivo ad un file. Gli altri client possono cosi' accedere
al file solo quando l'accesso esclusivo viene rilasciato.
L'integrazione di NFS nel sistema operativo del computer consente alle
applicazioni di lavorare in modo trasparente sui files remoti. Per
ottenere cio' nella configurazione di NFS si crea sul computer client
una particolare cartella, che viene associata al computer remoto dove
sono i files condivisi. Questa cartella riproduce un'immagine esatta
del file system del computer server NFS.
Quando un'applicazione accede ad un file su questa cartella speciale,
il sistema client-server NFS si fa da tramite per eseguire sul computer
remoto l'operazione richiesta, aggiornando anche la cartella locale.
⌡ 13.6 INTERNET ED IL WORLD WIDE WEB
----------------------------L'origine delle reti geografiche risale agli anni '60 quando il ministero
della Difesa USA creo' l'ARPA (Advanced Research Projects Agency).
Progressivamente s'inserirono universita' e organizzazioni di ricerca
civili creando la rete Arpanet sulla quale fu presto definito il protocollo
TCP/IP per permettere la connettivita' di macchine molto diverse tra loro.
Negli anni '60 e '70 furono sviluppate sia reti LAN (Local Area Network)
che WAN (Wide Area Network), ma con tecnologie di interconnessione tra loro
incompatibili, per cui lo scambio di informazioni poteva avvenire solo
all'interno di una stessa rete.
Internet e' stata sviluppata per consentire l'interconnessione tra reti
diverse e lo scambio di informazioni tra utenti, indipendentemente dai
computer o dalle reti utilizzate.
Questa connettivita' e' stata realizzata aggiungendo nella rete speciali
computer chiamati 'router' con il compito di connettere LAN e WAN di tipo
diverso. Ad essi si e' aggiunto anche un protocollo comune che uniformasse
il metodo di trasmissione dei dati, il protocollo TCP/IP.
Cosi' e' nata la rete delle reti: Internet.
La nascita di Internet puo' essere collocata nel 1983, quando da Arpanet
si distacco' la sezione militare, creando la sua rete Milnet.
Ma e' dopo il 1990, con il progetto WWW del CERN (World Wide Web, il
metodo ipertestuale e intuitivo per accedere alle risorse su Internet),
che nasce Internet com'e' oggi, con i browser HTML per la navigazione
su Web, il primo dei quali (Mosaic) nasce nel 1993. Con esso inizia la
crescita esponenziale di Internet, mostrata in figura:
N
30M
25M
20M
15M
10M
5M
^
│
├
│
│
├
│
│
├
│
│
├
│
│
├
│
│
├
│
│
.
.
Crescita esponenziale del numero
di calcolatori collegati a Internet
X
.
.
.
.
.
X
.
.
X
.
.
X
X
. X . X . X . X
0M
└──X───X───X───X───X───X───X───┴───┴───┴───┴───┴───┴───┴───┴───┴──
─>
1984
1986
1988
1990
1992
1994
1996
1998 Anno
Sia per l'elevato numero di computer collegati, sia perche' il percorso
di una connessione con un sito puo' essere variata dai computer istradatori
(router) non e' possibile avere su Internet una visione della rete come
quella che si ottiene nella rete locale con 'Risorse di rete'. Per questo
sono stati predisposti programmi, usati dagli amministratori delle reti,
che inviano messaggi sulla rete e ne esaminano le risposte ricevute.
Uno dei piu' semplici e' ping, che si usa eseguendo (per esempio):
ping www.sun.com
Altri programmi (per esempio 'traceroute'), inviando ripetutamente verso
il sito specificato messaggi (datagrammi IP) con un tempo di vita via
via crescente, ricevono in risposta messaggi di errore (per time-out, in
protocollo ICMP) dai vari router fino al sito indirizzato e possono cosi'
tracciare il percorso della connessione (uno di questi e' scaricabile dal
sito http://shareware.cnet.com.
Il World Wide Web costituisce un enorme deposito di informazioni a cui
gli utenti possono accedere tramite dei programmi interattivi chiamati
browser (sfogliatore di pagine). Questi sono applicazioni molto complesse
(percio' non ne esamineremo i dettagli), che ricevono dall'utente una
stringa URL (Uniform Resource Locator) nel formato:
protocollo://computer:porta/file
(il parametro :porta e' opzionale ed in genere viene omesso).
Da questa stringa di caratteri il browser puo' ricavare: il nome del
documento richiesto dall'utente (file), il nome del server dove risiede
ed il protocollo da usare.
I protocolli piu' usati, al livello di applicazione, sono HTTP (HyperText
Transport Protocol) ed FTP (File Transfer Protocol); entrambi si avvalgono
dei protocolli di trasporto TCP/IP.
Il browser puo' quindi richiedere al server HTTP di ricevere il documento
richiesto dall'utente e di visualizzarlo su video in modo corretto.
Per ottenere un'indipendenza dalla piattaforma (computer, scheda video,
ecc.) dell'utente (tutti possono accedere) si e' introdotta una codifica
dei testo a marcatori HTML (HyperText Markup Language): in questo modo si
danno al browser delle indicazioni di come impaginare il documento,
lasciando al browser l'implementazione nella particolare piattaforma di
queste indicazioni. Vedremo in seguito come questo avviene.
Internet, la rete delle reti, costituisce cosi' una rete fisica mondiale
di computer connessi a vari livelli, indipendente dalle diverse piattaforme
hardware, dai sistemi operativi e dalla localizzazione geografica.
I vari computer della rete sono in grado di riconoscersi e di scambiarsi
dati, grazie all'uso degli stessi protocolli di comunicazione.
Ogni computer client si collega direttamente con un computer server di
un gestore della connettivita' Internet (Societa' di servizi, chiamate
'provider'). Questi server gestiscono i servizi di rete, come FTP, HTTP,
Gopher, WAIS (per accesso a database su Internet) e quelli sulla sicurezza:
nelle sottoreti aziendali c'e' anche un 'Proxi' software che mette in atto
un servizio di protezione dell'accesso dall'esterno alle risorse della
sottorete aziendale, chiamato firewall.
Il server a cui l'utente e' direttamente collegato (quello del provider)
e' dedicato al riconoscimento delle chiamate nel giusto protocollo. Pero'
nella maggior parte dei casi la richiesta che gli arriva dal browser del
client e' diretta ad un altro server della rete mondiale Internet, dove
il documento richiesto dall'utente risiede.
Il server deve allora istradare la richiesta sulla inter-rete (Internet)
per farla arrivare a destinazione.
Questo server in genere e' connesso nella rete locale del provider ad un
altro computer (access server), che attraverso un router (istradatore),
con apposita interfaccia (per esempio X25, PAD, ecc.) si collega agli
altri server dei nodi di comunicazione della rete mondiale Internet
(vedi la descrizione delle inter-reti e del protocollo TCP/IP).
Ulteriori dettagli del funzionamento sistemistico di Internet, come pure
della descrizione delle sue funzionalita', esula dagli scopi di questo
corso.
I tipi di collegamento possibili ad Internet sono:
1) Collegamento permanente: con un 'router' ed una linea telefonica
dedicata si puo' collegare la propria rete LAN ad un host di un
'Internet access provider' (il router tradurra' i protocolli LAN/WAN
e istradera' il traffico tra le due reti).
2) Collegamento diretto su linea commutata: e' quello solitamente usato
da casa con protocollo PPP (che include la correzione degli errori a
livello di frame, evitando le ritrasmissioni).
3) Collegamento ad una rete privata via Internet (rete privata virtuale
VPN, Virtual Private Network), possibile solo se il client dispone di
un nome o indirizzo IP.
4) Collegamento in sola posta elettronica (come utenti di un servizio
BBS=Bulletin Board System)
5) Collegamento in emulazione di terminale: il software fa comportare il
computer client come un terminale di un computer server, permettendo
cosi' all'utente di lavorare sul computer server in maniera 'remota'.
6) Server privato di accesso remoto, che accetta connessioni da client
remoto via modem o Internet.
Essendo questa materia particolarmente ricca di sigle e nozioni, si
ritiene utile descrivere alcune sigle e nozioni di interesse per gli
studenti in Appendice A.
!----------------------------------------------------------------------CAPITOLO 14 - Programmazione ad oggetti e linguaggio Java
═══════════
Riassunto: In questo capitolo vengono spiegate le motivazioni principali
che hanno portato all'introduzione della programmazione ad
oggetti e viene introdotto il linguaggio Java, utile per
scrivere sia applet che vere e proprie applicazioni.
⌡ 14.1 - INTRODUZIONE
============
Iniziamo questo capitolo
risulteranno utili anche
per il quale e' previsto
sviluppo Java (JDK, Java
con una serie di informazioni preliminari, che
per organizzare il lavoro delle esercitazioni,
lo scaricamento dalla rete dell'ambiente di
Development Kit).
⌡ 14.1.1 - PREMESSA
-------Nel corso di Calcolatori Elettronici il linguaggio Java e' usato come
esempio di un linguaggio moderno, orientato agli oggetti, che pur
assomigliando al C++, e' relativamente piu' semplice da apprendere.
Come linguaggio orientato agli oggetti, Java supporta il multitasking,
cioe' la capacita' di elaborare simultaneamente piu' task, chiamati
'thread' (quindi si parla di multi-threading): per capirne l'utilita'
*
basta pensare alle animazioni nelle pagine Web (prodotte con Java applet).
Il linguaggio di programmazione Java e' stato sviluppato da Sun (vedi
il sito Internet di Sun: www.java.sun.com), l'azienda che nel 1991 per
prima ha iniziato a progettare il precursore di Java, un piccolo
linguaggio per microcomputer, da utilizzare in piccoli dispositivi come
gli elettrodomestici.
Per la progettazione di questo linguaggio gli autori trassero spunto dal
linguaggio UCSD Pascal, che Niklaus Wirth aveva lanciato commercialmente
nel mondo dei primi PC (Apple II) alla fine degli anni '70 e che produceva
un codice intermedio che poteva essere eseguito da qualsiasi computer che
fosse dotato dell'interprete per quel codice.
L'inizio della vera costruzione del linguaggio Java pero' risale all'autunno
1995, quando Netscape decise di abilitare all'uso di Java il suo browser
Navigator 2.0.
Subito dopo, nel gennaio 1996, Sun rilascio' la prima versione di Java
(ancora poco utilizzabile pero' per scopi professionali).
Bisogna attendere il 1998 per l'annuncio della versione Java 2 ed il 1999
*
per la sua disponibilita' come kit JDK 1.2 (attualmente e' scaricabile dal
sito di Sun la versione JDK 1.2.2).
Gli esempi riportati in queste dispense sono prevalentemente ispirati dalla
guida ufficiale di Sun Microsystems (ci si e' attenuti quanto piu' possibile
al testo per consentire al lettore di potervi fare riferimento con facilita'
per gli approfondimenti voluti):
Cay S.Horstman, Gary Cornell - Fondamenti di JAVA 2 - Mc Graw-Hill
Un differente approccio all'apprendimento del linguaggio di programmazione
Java si trova nel testo:
Cadenhead - Java programming in 24 hours - Ed. Sams Net
Entrambi i testi sono dotati di CD-ROM contenente l'ambiente di sviluppo
Java.
Scopo delle dispense e' di fornire solo una selezione degli argomenti di
maggiore interesse per il corso, tenendo presente che il nostro non e' un
corso di tecnica della programmazione e che lo spazio disponibile per lo
studio della programmazione Java e' molto limitato. Per questo motivo
lasceremo alla buona volonta' dello studente gli approfondimenti del
linguaggio Java, quali gli argomenti relativi ai 'thread' per il controllo
degli eventi AWT, la programmazione grafica, i componenti Swing per
l'interfaccia utente, ecc.
⌡ 14.1.2 - PREPARAZIONE DELL'AMBIENTE PER LE ESERCITAZIONI
----------------------------------------------Gli esempi piu' significativi riportati in queste dispense sono tutti nel
dischetto delle esercitazioni fornito dal docente e saranno usati nelle ore
di laboratorio.
Gli studenti sono incoraggiati a scaricare direttamente dal sito di Sun gli
strumenti di sviluppo della programmazione Java piu' recenti con la relativa
documentazione (messi a disposizione gratuitamente per tutta la durata del
corso): Java Development Kit (JDK), ecc.
Il software Java 2 SDK e' scaricabile dal sito:
http://developer.java.sun.com/developer/earlyAccess/j2sdk13/
I requisiti minimi del computer con Windows95/98/NT sono:
Pentium 166MHz, 32MB RAM e 65MB di spazio libero su disco
Si tenga presente che, data la rapida evoluzione di questo campo, la rete
(vedi www.java.sun.com) dev'essere considerata la sorgente primaria per
*
l'acquisizione delle informazioni su Java, poiche' la carta stampata ha
tempi di pubblicazione troppo lunghi, cosicche' al livello di progresso
tecnologico attuale risulta utile solo per un apprendimento istituzionale
dei concetti di base (vedi i testi consigliati).
La documentazione Java (Tutorial) e' scaricabile dal sito:
http://www.java.sun.com/docs/books/tutorial/information/download.html
La documentazione API (Application Programming Interface) e' consultabile
invece sul sito
/jdk/docs/api/index.html
Altri siti d'interesse si trovano elencati nel file README presente nella
directory jdk1.2.2
ATTENZIONE: Se si scarica la versione beta 1.4 bisogna sostituire dovunque,
in queste dispense:
\jdk1.2.2\... ----> \jdk1.4\...
*
CONSIGLIO: Si operi contemporaneamente su due finestre DOS di Windows.
Gli esempi riportati in queste dispense possono cosi' essere eseguiti
nella prima finestra DOS, mentre il testo delle dispense che li descrive
puo' essere visualizzato nella seconda finestra sullo stesso monitor.
Gli strumenti del JDK (Java Development Kit), scaricati dal sito della Sun,
operano in una finestra DOS, cioe' utilizzando il file system del sistema
operativo Windows, tramite i comandi dell'interprete COMMAND.COM (senza
interfaccia grafica).
Dopo aver scaricato la versione JDK ed averla decompressa ed istallata,
semplicemente con un doppio click sull'icona (con tutte le applicazioni
chiuse; se vi serve WinZip potete scaricarlo in versione shareware dal sito
www.pkware.com o dal CR-ROM del libro), si avra' la directory C:\jdk1.2.2
all'interno della quale, nella subdirectory 'bin', si troveranno il
compilatore 'javac.exe' e l'interprete del bytecode 'java.exe':
c:\jdk1.2.2\
|
+----\bin\ Programmi eseguibili jdk (javac, java, ecc.)
|
|
|
+---\ CognomeStudente\ Programmi dello studente
|
+---\demo\
|
+---\include\
|
+---\jre\
|
+---\lib\
Per non mescolare i file di esercizi, su cui uno studente lavora, con
quelli del jdk si raccomanda di creare all'interno di bin una subdirectory
con il proprio cognome (CognomeStudente): basta cliccare sul pulsante
destro e scegliere Nuovo e Cartella (New e Folder in inglese), battendoci
poi il proprio cognome.
Si lavorera' poi sempre dentro questa propria directory (un altro studente
che lavorera' su quel computer operera' cosi' solo all'interno di un'altra
directory: quella con il suo cognome).
Dopo aver aperto una finestra DOS (Start-->Programmi-->Prompt di MS-DOS) i
comandi da eseguire per cominciare a lavorare sono:
CD \jdk1.2.2\bin
MD ROSSI (Crea la directory ROSSI che conterra' solo il lavoro di Rossi)
CD ROSSI
Le volte successive lo studente Rossi all'inizio del lavoro, potra' mettersi
nella sua sub-directory con il comando CD \jdk1.2.2\bin\ROSSI.
Egli dovra' anche rendere accessibili ai programmi del jdk la biblioteca dei
programmi (*.exe) e delle classi (*.class) con le seguenti istruzioni batch:
PATH=c:\;c:\windows;c:\windows\command;c:\jdk1.2.2\bin
set CLASSPATH=c:\jdk1.2.2;c:\jdk1.2.2\InPackage;c:\jdk1.2.2\bin\ROSSI
c:
cd \jdk1.2.2\bin\ROSSI
Queste possono essere salvate, per comodita', in un proprio file batch
SETPATH.BAT, da mettere nella directory c:\jdk1.2.2\bin\ROSSI, per poter
essere piu' facilmente rieseguite con il comando batch SETPATH.
I files batch .BAT presenti nel dischetto delle esercitazioni si riferiscono
al jdk1.3 e vanno usati solo come esempi di riferimento.
N.B. IN NESSUN CASO SI DEVE ALTERARE IL FILE 'AUTOEXEC.BAT' DEL COMPUTER !
*******************************************************************
A questo punto lo studente Rossi e' pronto per operare in Java nella sua
finestra DOS, provando il programma PrimoEsempio con i passi seguenti:
1) Scrivere il programma sorgente Java con un editor (per esempio partendo
dall'esempio PrimoEsempio sul dischetto). Se il programma e' una classe
pubblica ed ha il nome PrimoEsempio (cioe' public class PrimoEsempio{...}
ecc.) va salvato con lo stesso nome ed estensione .java, cioe':
PrimoEsempio.java
2) Compilare questo file sorgente, eseguendo javac.exe, con il comando:
javac PrimoEsempio.java
Se non ci sono errori, la compilazione del file sorgente produce il
file PrimoEsempio.class (bytecode), altrimenti vengono segnalati gli
errori e si torna al punto 1 per la correzione battendo:
edit PrimoEsempio.java
(riferirsi al n. di riga in basso)
3) Se non ci sono errori, si puo' eseguire il programma compilato, avviando
l'interprete java del bytecode con il comando:
java PrimoEsempio
(.class si omette)
Il kit JDK e' molto sensibile alla struttura delle directories e quindi
alle impostazioni delle path (vedi libro a pag.693). Per controllarle si
puo' battere PATH e Invio.
Per ripristinare le impostazioni originarie riavviare il sistema.
Elenco dei programmi Java forniti sul dischetto delle esercitazioni:
SOURCE FILE (.java)
------------------PrimoEsempio
SecondoEsempio
DESCRIZIONE
----------Semplice programma di benvenuto
Esempio di programma con output di testo e numeri
TerzoEsempio
Root
NewRoot
Test0
QuoteLotto
Riordina
TestTry
SwapTest
SwapTest2
VirusLook
EmployeeTest
Parla
FileTest
FileCopy
InKeyb
ProvaBug
H6809h
Esempio con array di stringhe
Semplice programma per stampa radice quadrata
Semplice programma con if
Semplice programma per provare istruzioni
Esempio con input da tastiera e chiamata di metodo
Esempio con passaggio di array come parametri
Esempio di programma con gestione degli errori
Esempio con scambio parametri che non funziona
Esempio con scambio parametri che funziona
Esempio tipico di programmazione ad oggetti
Esempio tipico di programmazione ad oggetti
Esempio di programma ad oggetti con ereditarieta'
Esempio di programma con scrittura su disco
Esempio di programma con I/O su disco
Esempio di Package (InPackage) per input da tastiera
Programma con 2 errori da rimuovere
Programma Monitor scritto in Java (con oggetto Byte)
ESEMPI DI APPLET:
PrimoApplet.java
PrimoApplet.html
SecondoApplet.java
SecondoApplet.html
Esempio di Applet
Esempio di Pagina HTML per provare Applet
Esempio di Applet (con passaggio di parametri)
Es. di pag. HTML per test Applet (con pass.parametri)
ESEMPI GUI:
FrameTest.java
CloseTest.java
IconTest
PulsTest.java
TestEvent.java
Esempio di apertura di un frame
Esempio di apertura di un frame
Esempio di apertura di un frame
Esempio di apertura di un frame
Es. di apertura di un frame con
COMUNICAZIONE IN RETE:
httpServer.java
Esempio di realizzazione di un server HTTP
chiudibile
con immagine
con 3 pulsanti
eventi (3 pulsanti)
Inoltre, se si dispone del CDROM del testo (Horstmann), i sorgenti di tutti
gli esempi riportati nel libro sono anche disponibili nella directory del
package \jdk1.2.2\corejava (con le indicazioni di volume e capitolo del
libro), per cui non occorre perdere tempo per digitare gli altri sorgenti
degli esempi presenti sul libro.
Siccome per comodita' in Java si usano spesso nomi lunghi (che renderebbero
scomoda la digitazione dei comandi DOS), si ricordi che e' possibile lanciare
velocemente editing, compilazione ed esecuzione di un programma come
QuoteLotto.java nella finestra DOS ricorrendo ad uno dei due modi di lavoro
seguenti:
a) Eseguire l'utility DOSKEY, che memorizza la cronologia dei comandi
battuti su tastiera e li ripresenta battendo 'freccia su' e 'freccia
giu' (battendo i primi caratteri del comando e poi F8 questo viene
trovato e completato); per inserire DOSKEY stabilmente potete mettere
DOSKEY /INSERT nell'AUTOEXEC.BAT del vostro computer di casa (non in
quello del laboratorio).
b) Creare i 3 files batch seguenti di 1 sola riga nella directory di lavoro
(esempio: \jdk1.2.2\bin\ROSSI):
FILE
---e.bat
c.bat
r.bat
RIGA (esempio)
-------------edit QuoteLotto.java
javac QuoteLotto.java
java QuoteLotto
COMANDO DOS (ABBREVIATO)
-----------------------e (edit)
c (compila)
r (run)
Si possono inoltre usare contemporaneamente due diverse finestre DOS, una
per editare le correzioni e l'altra per lanciare facilmente la compilazione
con il tasto di richiamo del precedente comando di compilazione.
Se il package InPackage (libreria delle classi pubbliche per input da
tastiera), oppure Corejava importato da molti file delle esercitazioni
del libro, non sono raggiungibili dalla directory corrente, si deve
eseguire l'istruzione:
set CLASSPATH=c:\jdk1.2.2\bin\InPackage (oppure Corejava)
(che e' inserita nel file batch SETPATH.BAT sul dischetto degli esercizi).
N.B. Volendo, l'editor EDIT della finestra DOS puo' anche caricare piu'
di un programma in memoria (fino a 9) ed operare passando dall'uno
all'altro con i tasti Alt-1, Alt-2, ecc.
Un metodo di lavoro alternativo viene fornito dall'editor TextPad, fornito
shareware con il jdk1.2.2 da Sun. Con esso si puo' fare editing e poi
avviare compilazione e run (del JDK), con i tasti Ctrl-1 e Ctrl-2.
⌡ 14.1.3 - PRESENTAZIONE DI JAVA
--------------------Java e' un linguaggio moderno, orientato agli oggetti, che pur assomigliando
*
al C++, e' relativamente piu' semplice da apprendere.
E' inoltre un linguaggio molto portabile, in grado di operare su ogni
piattaforma, come serve sul Web (l'ingresso di Java su Internet risale
al 1994, anno in cui SUN sviluppo' il primo browser scritto interamente
in Java, chiamato HotJava).
La programmazione ad oggetti si presenta come una metodologia di
fondamentale importanza, soprattutto nei casi di lavoro di piu' persone
*
in collaborazione su progetti di notevole entita'.
I linguaggi ad oggetti, come Java, spingono a rispettare la disciplina
di programmazione necessaria in questi casi, facilitando cosi' il lavoro,
riducendo il 'debugging' necessario e migliorando la manutenibilita' dei
sistemi.
Il processo di creazione, compilazione ed esecuzione di programmi Java
avviene nel modo seguente.
Il codice sorgente Java viene:
- scritto con un normale editor;
- compilato con un programma compilatore (javac), specifico della macchina
su cui si lavora (es. Pentium, Power PC, SPARC). La compilazione fornisce
un codice binario in un formato standard, che puo' essere riconosciuto
ed eseguito da un interprete Java, in modo indipendente dalla piattaforma,
in quanto la specificita' della piattaforma (processore, sistema operativo,
ecc.) risulta contenuta esclusivamente nel programma interprete JVM (Java
Virtual Machine). A differenza di quanto accade con gli altri linguaggi,
come C++ e Pascal, il codice risultante dalla compilazione Java non e'
quindi formato dalle istruzioni binarie della macchina su cui si lavora,
ma da uno speciale codice standard, chiamato Bytecode, attraverso il quale
*
si ottiene l'indipendenza dalla piattaforma, che e' cosa importantissima
per l'uso dei programmi sul Web);
- eseguito da un interprete Java (JVM), specifico della macchina ospite,
che puo' anche far parte del browser di accesso ad Internet;
I programmi Java si dividono in due categorie:
1) APPLICAZIONI: sono programmi autonomi sviluppati in Java, eseguibili
sulla macchina dell'utente (sotto interprete Java o anche in forma
eseguibile, dopo la compilazione in istruzioni macchina);
2) APPLET: sono programmi (Java applets) scaricati, all'interno di pagine
Web, da un server remoto dove risiedono, ed eseguiti sulla macchina
locale all'interno del browser (che deve contenere l'interprete Java),
quando l'utente accede alle pagine Web che contengono applets Java.
In questo modo si puo' programmare sul Web, rendendo interattive le sue
pagine (vedi la classe URL di Java, per accedere al Web: sul testo
Horstmann ⌡10.4, pag.549).
⌡ 14.1.4 - UN PRIMO ESEMPIO
----------------
Riferiamoci come esempio alla semplice applicazione seguente:
/*
* Questo e' un esempio di
* commento su piu' righe
*/
public class PrimoEsempio
{ public static void main (String[] args)
{ System.out.println("Benvenuto nell'ambiente di programmazione Java");
}
} // Fine del programma
Possiamo fare le seguenti osservazioni iniziali:
*
1) Java fa distinzione tra Maiuscole e minuscole (l'ambiente DOS no);
2) Usa // per commento su 1 riga; /* ... */ per blocco di righe di
commento (non annidabile con altri /* ... */ interni al blocco);
si puo' anche usare /** ... */ per la generazione automatica di
documentazione con l'utility javadoc;
3) { } definiscono un blocco del programma (come la coppia BEGIN...END
in Pascal); per batterle, se sulla tastiera manca il tasto, fare
Alt-123 e Alt-125 sul tastierini numerico;
4) Il programma viene chiamato 'class'; i sottoprogrammi si chiamano
'metodi';
5) La parola chiave 'public' (modificatore di accesso) determina quali
altre parti del programma possono avere accesso a questa classe;
6) Il nome della classe (PrimoEsempio) non dev'essere una parola riservata
e per convenzione (comunemente usata) comincia con una lettera maiuscola
seguita da lettere o numeri (lunghezza qualsiasi), mentre i nomi dei
metodi iniziano con lettere minuscole;
7) Il nome del file su disco (sorgente) dev'essere uguale al nome della
classe con estensione .java (nell'esempio dev'essere PrimoEsempio.java),
se public;
8) La riga { System.out.println("Benvenuto..."); } costituisce la chiamata
al metodo 'println' dell'oggetto 'System.out' con argomento (=parametro)
"Benvenuto...". Questo blocco, costituente il corpo del programma
PrimoEsempio, e' fatto di una sola istruzione (terminata dal punto e
virgola). Esiste anche il metodo 'print' dell'oggetto 'System.out'
che non avrebbe aggiunto il ritorno a capo e va usato per produrre piu'
output sulla stessa riga (sono gli analoghi delle procedure 'writeln'
e 'write' gia' incontrate in Pascal).
La sintassi usata in questo caso di chiamata al metodo 'println'
dell'oggetto System.out e' un esempio di quella valida in generale
per la chiamata ai metodi (=sottoprogrammi) degli oggetti.
Cioe' per chiamare il metodo di un oggetto si dovra' sempre scrivere:
Oggetto.metodo(parametri)
9) La compilazione del file sorgente PrimoEsempio.java si puo' avviare,
come gia' detto, in una finestra DOS con il comando:
javac PrimoEsempio.java
Se non ci sono errori, la compilazione del file sorgente produce il
file PrimoEsempio.class (bytecode);
10) L'esecuzione del programma compilato si otterra' invece avviando
l'interprete java con il comando:
java PrimoEsempio
(.class si omette)
11) All'avvio dell'applicazione PrimoEsempio il controllo viene passato
al metodo main, che acquisisce eventuali parametri via String[] args
(cioe' args[0] , args[1] , ecc.: vedi l'esempio NewRoot piu' oltre);
12) Se invece di un'applicazione si programma un'applet, questa sul WEB
e' prima downloaded (come bytecode) insieme alla pagina HTML che la
contiene e poi eseguita sulla macchina client dall'interprete contenuto
nel browser; per la messa a punto della programmazione dell'applet
l'ambiente di sviluppo (JDK) mette a disposizione un apposito programma
(chiamato 'appletviewer'), che sostituisce l'interprete Java del browser
sulla macchina client, permettendo un collaudo rapido, con l'uso di
un apposito file HTML, in cui l'applet viene inserita (evita cioe' di
dover istallare la pagina in rete, sul server Web, per poter provare
il programma dell'applet); vedremo Root e RootApplet come esempi di
cio'.
13) La parola chiave 'void' si mette nei metodi che non hanno paramentri
in uscita, ma che possono variare attributi di classe o di oggetto
(=COMMON). Senza 'void' equivalgono alle FUNCTION del Pascal; con
'void' sono equivalenti alle PROCEDURE del Pascal.
⌡ 14.1.5 - Come si lavora in JAVA:
----------------------I programmi Java sono orientati agli oggetti ( OOP = Object Oriented
Programming). Questo significa (come spiegheremo meglio poi) che in
JAVA si programmano le classi, che contengono oltre ai dati (attributi
dell'oggetto), anche i metodi (sottoprogrammi che definiscono le
funzionalita' dell'oggetto).
Per esempio posso scrivere una classe Cane, che definisce gli attributi
ed i metodi applicabili agli oggetti 'cane'.
In un metodo (costruttore), con le istruzioni 'new', si istanziano gli
oggetti, ovvero si alloca loro memoria per poterci lavorare (da quel
momento in poi): cioe' con la classe Cane istanzio gli oggetti con cui
il mio programma dovra' lavorare (per esempio Cocker e Boxer).
Quindi in Java prima si creano gli oggetti (=istanze della classe), usando
*
le istruzioni 'new'; ogni oggetto istanziato viene identificato con la sua
variabile oggetto (=nome identificatore dell'oggetto).
Poi gli si attribuisce lo stato iniziale e quindi si lavora con gli oggetti
(come fossero nuovi tipi di variabili), referenziandoli con il nome della
variabile oggetto ed eseguendo chiamate ai metodi delle classi.
OGGETTO = Nuovo tipo di variabile (definito con la class) che comprende
oltre ai dati (=attributi dell'oggetto) anche le sue funzionalita'
(=metodi dell'oggetto)
CLASSE = Programmi che rappresentano la definizione formale di un oggetto
(main = inizio del 'main program', e' quello lanciato al RUN)
|--> ATTRIBUTI (dati, parametri in/out)
OGGETTO-->|
(CLASS=Master copy dell'oggetto)
|--> METODI (Funzionalita', comportamento, istruzioni)
Esempio:
public class Cane
<---- class usabile per creare oggetti 'Cane'
{ String name;
<---- crea string variable 'name'=ATTRIBUTO
public void parla()
<---- parla()=METODO (=comportamento dell'oggetto)
{ System.out.println("Bau! Bau!");
}
<--- fine sottoprogramma parla (=Metodo di Cane)
}
<--- fine programma Cane (=Master copy degli oggetti 'Cane')
Uso:
CREAZIONE DELL'OGGETTO 'Cocker':
Cane Cocker= new Cane();
CREAZIONE DELL'OGGETTO 'Boxer'
Cane Boxer = new Cane();
ASSEGNAZIONE DEGLI ATTRIBUTI A 'Cocker':
Cocker.name="Chicca";
USO DELLA VARIABILE 'name' dell'oggetto 'Cocker':... Cocker.name ...
RICHIAMO DEL METODO 'parla' dell'oggetto 'Cocker': Cocker.parla();
Esempio: l'istruzione
Cocker.parla();
produce in output "Bau! Bau!")
<-Oggetto-><-metodo->
Attenzione: il termine 'oggetto' viene di solito usato indifferentemente
per indicare sia la classe (oggetto Cane), che le istanze
della classe (oggetti Cocker, Boxer): questo non deve generare
confusione.
Nell'esempio considerato Cane e' l'analogo del 'type', mentre Cocker e
Boxer sono le variabili-oggetto usabili per referenziare le due istanze
dell'oggetto Cane, definito dalla classe sopra esemplificata (master copy
dell'oggetto, cioe' matrice con cui creare le varie istanze di Cane, che
sono quelle con cui lavora l'applicazione).
Queste istruzioni vengono usate nella classe Parla.java (descritta anche
piu' oltre come esempio di ereditarieta'), presente sul dischetto delle
esercitazioni. La riportiamo anche qui' come esempio di programmazione
con due oggetti Cane e Uomo, dei quali prima si creano le istanze Studente
e Cocker (con 'new'), poi si elaborano (nel main), referenziandole con le
rispettive variabili-oggetto Studente e Cocker (esempio: Cocker.dorme ).
La procedura seguita (nel main) e' quindi:
1) Si creano le due istanze di Cane e Uomo e si definiscono le relative
variabili-oggetto Studente e Cocker;
2) si elaborano le due istanze definendo il valore dell'attributo 'name'
*
(comune a entrambi gli oggetti) ed usando i metodi 'parla' (diverso
nei due oggetti) e 'dorme' (comune a entrambi gli oggetti).
/* ==== Esempio di definizione di oggetti (con ereditarieta') ====
* La routine con il metodo 'dorme' e' comune a Cane e Uomo
* (e' cosi' scritta una sola volta)
*/
class Parla
{
// --- Classe (madre) degli oggetti Dormiente (con metodo 'dorme') --public static class Dormiente
{ String name;
public static void dorme() // <--- metodo dorme (comune a Cane e Uomo)
{ System.out.println ("zzzzzzzzzzzzzz");
}
} // Fine della classe Dormiente
// --- Classe (figlia) degli oggetti 'Cane' con metodo 'parla'--public static class Cane extends Dormiente
{ public static void parla() // <--- Metodo parla di Cane
{ System.out.println("Bau! Bau!");
}
}
// --- Classe (figlia) degli oggetti 'Uomo' con metodo 'parla'--public static class Uomo extends Dormiente
{ public void parla() // <--- Metodo parla di Uomo
{ System.out.println("Nel mezzo del cammin di nostra vita....");
}
}
// --- Programma principale --public static void main (String arguments[])
{ // --- Definiz.oggetti Cocker e Studente --Cane Cocker = new Cane();
Uomo Studente=new Uomo();
// --- Assegnazioni attributo name --Cocker.name = "Chicca";
Studente.name = "Mario";
// --- Inizio esecuzione --System.out.println ("Ora parla " + Studente.name + ":");
Studente.parla();
System.out.println ("Ora parla " + Cocker.name + ":");
Cocker.parla();
System.out.println ("Ora dormono entrambi:");
Cocker.dorme();
Studente.dorme();
}
} // Fine della classe Parla
L'output prodotto dall'esecuzione del main e'
"Ora parla Mario:"
"Nel mezzo del cammin...."
"Ora parla Chicca:"
"Bau! Bau!"
"Ora dormono entrambi:"
"zzzzzzzzzzzzzz"
"zzzzzzzzzzzzzz"
⌡ 14.2. ELEMENTI DEL LINGUAGGIO DI PROGRAMMAZIONE JAVA
==============================================
⌡ 14.2.1 - TIPI DI VARIABILI
----------------Le variabili devono sempre essere dichiarate prima dell'uso.
*
In Java le variabili vanno dichiarate con il loro tipo (come in Pascal e
C++).
Le dichiarazioni possono comparire in qualsiasi punto del blocco di un
metodo, ma una sola volta.
Ogni variabile dichiarata entro {...} non puo' essere usata fuori del
blocco definito da {...} (variabile locale). Esistono pero' le variabili
di classe (vedi poi) che svolgono il ruolo di variabili globali della
classe (se sono public anziche' private, sono vere variabili globali,
accessibili a tutti i metodi dell'applicazione).
I blocchi possono essere annidati uno dentro l'altro (programmazione
strutturata), ma non si puo' ridichiarare la stessa variabile gia'
dichiarata in un blocco annidato.
Le variabili dichiarate in un metodo non possono essere usate in altri
metodi (variabili locali), a meno che non siano dichiarate come 'object
variable' o come 'class variable', cioe' subito dopo la dichiarazione di
classe all'inizio del programma (public static).
Le variabili possono essere dichiarate:
'private'
'private protected'
'public'
'static'
Esempi:
se possono essere modificate solo all'interno della
class;
se possono essere modificate solo nella class o in
ogni sottoclasse figlia derivata dalla class (magari
da altri programmatori, che possono cosi' usare la
class, anche all'insaputa del suo autore: quindi
occorre fare attenzione quando si usa il modificatore
'protected');
se possono essere modificate da altri programmi che
usano l'oggetto Virus;
se sono variabili di classe, cioe' comuni a tutti gli
oggetti creati dalla classe.
// Master copy degli oggetti 'Virus':
public class Virus {
integer maxFileSize=30000;
public integer newSeconds=86;
public String author = "Manzoni";
private protected int Minute = 30;
private int Hour = 12;
// Definizione oggetto 'influenza' (nuova istanza):
Virus influenza = new Virus();
// Assegnazione valore alla variabile newSeconds:
influenza.newSeconds = 92;
Metodi e variabili sono richiamabili con un '.' dopo l'oggetto.
Esempi:
influenza.newSeconds = 92;
(variabile)
Cocker.parla();
(metodo)
VARIABILI OGGETTO:
maxFileSize, newSeconds, author e Minute sono 'object variables', cioe' ce
n'e' una distinta copia per ogni oggetto creato dalla classe Virus.
VARIABILI DI CLASSE (sono globali per la classe, come un COMMON):
Le 'class variables', definite con lo statement 'static', invece sono comuni
a tutti gli oggetti creati dalla classe Virus (cioe' come se fosse un
COMMON /Virus/...):
Esempio:
static int virusCount = 0;
Le variabili sono gli attributi della classe o dell'oggetto.
Per indicare i numeri esadecimali si usa il prefisso 0x (esempio: 0xCAFE).
Sono disponibili 8 tipi standard (=essenziali): 6 numerici e 2 non numerici.
*
Numeri interi (signed):
(non ha tipi unsigned)
byte
short
int
long
Numeri in virgola mobile: float
double
Caratteri:
('H' e' un carattere,
"H" e' una stringa
di 1 solo carattere)
Variabili logiche:
1
2
4
8
4
8
byte
byte
byte
byte
byte
byte
(da -128 a +127)
ecc.
(esempio: 845623400123L)
(esempio: 3.45F)
(esempio: 3.45 o 3.45D)
Normalmente Java usa la doppia
precisione (che segue la specifica
IEEE 754).
char
2 byte (Unicode: vedi sito www.unicode.org;
codifica di 65536 caratteri internazionali di cui circa 35000 usati;
i primi 256 sono gli stessi della
codifica ASCII/ANSI)
boolean (ha 2 valori: true e false)
Esempi di dichiarazioni di variabili:
byte b;
int i,j,unaVariabileIntera;
long x,y; //doppia precisione (usata normalmente)
char ch; // Solo dichiarazione
char ch='A'; // Dichiarazione + inizializzazione
Tutti i tipi standard hanno classi corrispondenti (oggetti wrapper):
Integer, Long, Float, Double, Byte, Character, Void e Boolean (per esempio
esiste la classe Integer, che corrisponde al tipo essenziale int; il loro
uso non ci interessa per ora; ulteriori dettagli si trovano sul libro a
pag.179).
Il nome di una variabile e' un simbolo introdotto dal programmatore a
suo piacere (generalmente e' un nome mnemonico che aiuta a ricordare il
significato della costante o variabile) ma nel rispetto della sintassi
definita dal diagramma seguente (impone che inizi con una lettera):
┌─────────┐
┌<─────│ Lettera │<─────┐
│
└─────────┘
│
│
┌─────────┐
│
Nome ───>┼─────>│ Lettera │──────┼────>
│
└─────────┘
│
│
┌─────────┐
│
└<─────│ Cifra │<─────┘
└─────────┘
I caratteri possono essere in numero qualsiasi e sono tutti significativi,
*
compresa la differenza tra lettere maiuscole e minuscole. Non si possono
ovviamente usare i nomi riservati (elencati nell'appendice del libro).
⌡ 14.2.2 - ASSEGNAZIONI
-----------Tutte le variabili dichiarate vanno inizializzate con un'assegnazione
del valore iniziale che puo' essere fatta con un'apposita istruzione di
assegnazione di valore:
int i; // Dichiarazione
i=10; // Assegnazione (equivale al := del Pascal)
Java consente di assemblarle in un'unica istruzione di inizializzazione:
int i=10; // Inizializzazione
⌡ 14.2.3 - CONVERSIONI DI TIPO
------------------Si possono fare operazioni con tipi numerici diversi; saranno eseguite dopo
una conversione automatica al tipo di precisione maggiore.
Le conversioni per attribuzione forzata di tipo (chiamate cast) possono dar
luogo a perdita di precisione (per troncatura o arrotondamento).
La sintassi dei cast prevede l'uso del tipo di destinazione tra parentesi
seguito dal nome della variabile da convertire.
Esempio:
double x=9.96;
int n=(int)x;
La variabile n ha il valore 9 perche' (int) tronca i decimali.
Se si vuole invece l'arrotondamento si deve usare il metodo Math.round:
Esempio:
double x=9.96;
int n=(int)Math.round(x);
(int) serve perche' Math.round restituisce un risultato di tipo long.
⌡ 14.2.4 - COSTANTI
-------Le costanti devono avere dichiarazioni con nomi fatti di tutte lettere
maiuscole, precedute dalla parola chiave 'final'.
Esempio:
final double PI=3.14159265; // Pi greco
Di solito le costanti sono usate da piu' metodi all'interno di una classe.
In questi casi si chiamano 'costanti di classe' e vanno dichiarate con
l'aggiunta della parola chiave 'static'.
Se poi si vuole che anche altri metodi Java esterni alla classe possano
usare la costante, si aggiunge la parola chiave 'public' (specificatore
di accesso).
Esempio:
public class UsaCostante
------> { public static final double G=9.81; // Costante di gravita'
public static void main (String[] args)
{ System.out.println(G+" m/sec^2");
}
}
Riepilogando, in questo esempio, sulla riga indicata dalla freccia, le
parole chiave hanno il significato seguente:
public:
static:
final :
double:
altri metodi Java esterni alla classe possono usare la costante
la costante puo' essere usata da piu' metodi all'interno della classe
il valore non puo' essere cambiato (costante)
dichiarazione del tipo
⌡ 14.2.5 - OPERATORI
--------I quattro operatori aritmetici sono +-*/
La divisione tra interi si fa con lo stesso operatore / mentre per ottenere
il resto si usa % (anziche' 'mod' del Pascal).
Esempio:
15/4 fornisce 3;
15 % 4 fornisce 3.
Gli operatori aritmetici si possono usare nelle dichiarazioni:
int n=5;
int a=2*n; // a inizializzato a 10
L'assegnazione x+=4; equivale alla x=x+4;
Cio' vale anche per gli altri operatori (in tal caso vanno sempre posizionati
prima del segno =).
Esempi:
*=
oppure
%=
Altre funzioni matematiche, come l'elevamento a potenza, la radice quadrata,
il valore assoluto, ecc. sono disponibili come metodi della classe Math in
*
Java.lang
Esempi:
double z = Math.pow(x,y); // per z=x^y
double x= Math.sqrt(number);
int n=(int)Math.round(x);
ecc.
Sono anche disponibili gli operatori di incremento (++) e di decremento (--),
sia nella forma di suffisso che di prefisso (priorita' all'incremento).
La loro definizione si capisce subito dagli esempi seguenti:
int n=12;
int m=7;
n++; // Ora n e' 13
int n=7;
int a=2*++m; // Ora e' a=16, m=8
int b=2*n++; // Ora e' b=14, n=8
Gli operatori di incremento (++) e decremento (--) sono applicabili alle
variabili ma non ai numeri (4++ non e' ammesso).
⌡ 14.2.5.1 - OPERATORI LOGICI
---------------Producono un risultato logico true o false. Oltre ai soliti <,<=,>,>= ci
sono gli operatori:
== (uguaglianza)
!= (disuguaglianza)
&& (AND)
|| (OR)
! (NOT)
Esempio di uso:
if (args.length() == 2) { ecc. }
⌡ 14.2.5.2 - OPERATORI SUI BIT
----------------Producono un risultato intero operando singolarmente su tutti i bit (in modo
booleano). Sono:
&
(AND)
|
(OR)
~
(NOT)
<----- (se manca il tasto fare Alt-126)
^
(XOR)
<< (Shift Left)
>> (Shift Right, estendendo il segno)
>>> (Shift Right, riempiendo con zeri a sinistra)
<<< (non esiste)
Esempi: int n=9;
int Bit2alla3=(n & 8)/8; // Risultato=1 (quarto bit da destra)
int n=1<<3; // Risultato=8
int Bit2alla3=(n & (1<<3))>>3; // Risultato=1 (quarto bit da destra)
⌡ 14.2.5.3 - GERARCHIA DEGLI OPERATORI
------------------------L'ordine di esecuzione delle operazioni, se non diversamente imposto con
le parentesi tonde, segue nell'associativita' l'ordine di precedenza
indicato nella tabella seguente:
Associativita': da SINISTRA a DESTRA (salvo le 2 righe indicate)
Priorita'┌────────────────────────────────────
Massima │ [],(chiamata metodo)
│ !,~,++,--,+,-,(cast),new
<---- Associativita' invertita
│ *,/,%
( DA DESTRA A SINISTRA )
│ +,-
│
│
│
│
│
│
│
│
│
Minima
<<,>>,>>>
<,<=,>,>=,instanceof
==,!=
&
^
|
&&
||
?:
│ =,+=,-=,*=,/=,%=,&=,|=,^=,<<=,>>=,>>>=
<--- Assoc. invertita
(DA DESTRA A SINISTRA)
⌡ 14.2.6 - STRINGHE DI CARATTERI
--------------------In Java non esiste il tipo stringa, ma una classe String predefinita nella
*
libreria standard, per cui ogni stringa racchiusa tra virgolette e' una
istanza della classe String. Esempi:
String v=""; // stringa vuota
String saluto="Ciao"; // stringa piena
Le stringhe sono composte da sequenze di caratteri Unicode.
*
Operatori sulle stringhe:
------------------------1) Operatore di concatenamento (+): agisce oltre che con stringhe, anche con
numeri (che vengono trasformati in stringhe prima del concatenamento).
Questa proprieta' e' molto comoda nell'output di stringhe e numeri.
Esempio:
System.out.println("Ci sono " + virusCount + " virus.");
2) Sottostringhe: si ricavano con il metodo substring(n1,n2) della classe
String, dove n1,n2 sono i caratteri da prelevare: da n1 fino a n2-1
(n2 e' escluso, cosi' la lunghezza della stringa risultante e' n2-n1).
Esempio:
String saluto="Ciao";
String s=saluto.substring(0,3); // Crea s="Cia"
Si ricordi che il numero d'ordine dei caratteri parte da 0 e non da 1
(da sinistra a destra).
3) Lunghezza di una stringa: e' fornita dal metodo length() della classe
String. Esempio:
String saluto="Ciao";
int n=saluto.length(); // n=4
4) Carattere in una stringa: si puo' prelevare, oltre che con il metodo
substring(n,n+1), anche con il metodo charAt(n) della classe String.
E' anche possibile trasferire tutti i caratteri di una stringa in un
array di caratteri, piu' comodo nella programmazione dei loop.
Esempio:
String frase = "bla bla";
char lettere = frase.toCharArray();
I vari caratteri nella stringa 'frase' sono cosi' referenziabili come
lettere [n]
con n = 0...lettere.length()
5) Modifica di una stringa: si ottiene modificando la variabile di stringa
(es. saluto) facendola puntare ad una nuova stringa costruita con i
metodi del caso. Esempio:
String saluto="Ciao";
saluto = saluto.substring(0,3)+"k!"; // Ottiene saluto="Ciak!"
<------ nuova stringa ----->
6) Gestione delle stringhe in Java:
La creazione della nuova stringa invece della modifica di quella gia'
esistente richiede un'elaborazione piu' lunga, ma questo svantaggio e'
compensato dalla possibilita' di condivisione delle stringhe (presenti
una sola volta in memoria) tra vari oggetti, resa possibile proprio
dalla immutabilita' degli oggetti della classe String, prevista dalle
specifiche.
La creazione di sempre nuove stringhe come conseguenza delle varie
modifiche lascia un certo numero di stringhe inutilizzate (perche'
non piu' puntate da alcuna variabile di stringa) in memoria, per cui
si avrebbe un impegno di memoria crescente da parte del programma.
A cio' pensa la parte runtime di Java che provvede automaticamente
al recupero della memoria non piu' utilizzata con un processo di
'garbage collection'.
Per i casi in cui la manipolazione delle stringhe e' pesante ed i
vantaggi della condivisione minimi (per esempio l'assemblaggio in
una stringa di singoli caratteri provenienti da tastiera o da un
file), Java mette a disposizione un'apposita classe StringBuffer,
che permette la manipolazione diretta delle stringhe.
7) Comparazione di stringhe: il confronto tra stringhe (sia variabili
*
che costanti) si fa con i metodi 'equals' e 'equalsIgnoreCase'.
Esempi:
s.equals(t)
"Ciao".equals(command)
(restituiscono true o false)
"Ciao".equalsIgnoreCase("ciao")
Non si deve usare == per il confronto di stringhe. Per esempio:
if (saluto=="Ciao")... confronta solo se le stringhe sono memorizzate
nella stessa posizione di memoria (se lo sono, sono uguali, ma
potrebbero essere uguali anche se memorizzate in posizioni diverse!).
Il bug risultante dall'uso di == nel confronto tra stringhe sarebbe dei
peggiori: intermittente e che sembra verificarsi casualmente!
La classe String contiene oltre 50 metodi. Quelli ritenuti piu' utili
sono elencati nelle specifiche API (Application Programming Interface)
della classe java.lang.String (a pag.58 del testo). L'elenco completo si
puo' trovare nella documentazione in linea.
⌡ 14.2.7 - LETTURA DELL'INPUT DA TASTIERA
-----------------------------L'input in Java si fa agevolmente con programmi grafici che raccolgono
i dati attraverso una finestra di dialogo appositamente predisposta.
Cosi' non e' per l'utente che vuole scrivere semplici programmi senza
l'uso dell'interfaccia grafica (come abbiamo fatto con il Pascal), per
imparare il linguaggio. In tal caso la lettura dell'input da tastiera
risulta infatti piuttosto difficile, a meno che non si predispongano
delle specifiche routines, scritte per agevolare questo compito.
Per risolvere questo problema della didattica di Java ci scriviamo
percio', una volta per tutte, un nostro package (InPackage) contenente
la classe InKeyb, che mette a disposizione dell'utente i seguenti 3
metodi (per leggere interi, double e stringhe):
leggiInt, leggiDouble e leggiString
con cui potremo leggere una stringa da tastiera nel modo seguente:
String riga;
riga = InKeyb.leggiString("Stringa=");
In conclusione, usando la classe InKeyb, inserita nel package InPackage
(vedi la direttiva 'import'), l'input da tastiera di un numero
floating point in doppia precisione si puo' eseguire e provare con il
semplice programma seguente:
import InPackage.*;
public class InKeybTest; // Legge un numero da tastiera
{ public static void main(String[] args)
{ double x=InKeyb.leggiDouble ("Numero =");
System.out.println(x);
}
}
⌡ 14.2.8 - DISPLAY DELL'OUTPUT SU VIDEO
----------------------------
*
L'output prodotto dal metodo System.out.print(x) ha tutte le cifre
significative della variabile x e questo non permette un'ottimale
presentazione dei dati (per esempio incolonnati in tabelle).
Per questo e' opportuno formattare l'output in modo appropriato.
La classe NumberFormat del package java.text provvede i tre metodi
formattatori standard sotto elencati per numeri, valute e percentuali,
che restituiscono un oggetto di tipo NumberFormat (nf nell'esempio
seguente), a cui puo' essere applicato il metodo 'format' per ottenere
il numero nel giusto formato (vedi esempio).
I tre metodi formattatori sono:
NumberFormat.getNumberInstance()
NumberFormat.getCurrencyInstance()
NumberFormat.getPercentInstance()
Esempi:
per i numeri
per la valuta
per le percentuali
double x=10000/3
System.out.print(x); // Stampa 3333.3333333333335
double x=10000/3
NumberFormat nf=NumberFormat.getNumberInstance();
String fx=nf.format(x); // In ambiente USA fx="3,333.33"
System.out.print(fx); // Stampa 3,333.33
Il numero minimo e massimo del numero di cifre intere e frazionarie si
puo' impostare con i seguenti metodi della classe NumberFormat:
setMinumumIntegerDigits()
setMaximumIntegerDigits()
setMinumumFractionDigits()
setMaximumFractionDigits()
Esempio:
double x=10000/3
NumberFormat nf=NumberFormat.getNumberInstance();
setMinumumIntegerDigits(6)
setMaximumFractionDigits(4)
String fx=nf.format(x); // In ambiente USA fx="3,333.33"
System.out.print(fx); // Stampa 003,333.3333
E' anche possibile formattare definendo l'oggetto DecimalFormat che produce
il formato stabilito con l'apposita stringa in argomento. Esempio:
DecimalFormat df=new DecimalFormat("0.######")
System.out.print(df.format(x)); // Stampa 3333.333333
I caratteri usabili per la formattazione in DecimalFormat sono riportati
nelle tabelle 3.5 e 3.6 del testo.
⌡ 14.2.9 - ISTRUZIONI PER IL CONTROLLO DI FLUSSO
------------------------------------1) ISTRUZIONE IF:
if (condizione) istruzione;
-------------if (condizione) { blocco };
if (condizione) {blocco1} else {blocco2};
2) OPERATORE ? :
condizione? x:y; // Vale x se condiz.=true, y se false
------------3) LOOP INDETERMINATI: while (condizione) { blocco }; // Test condiz. prima
------------------- do {blocco} while (condizione); // Test condiz. dopo
4) LOOP DETERMINATI: for (istruzione1; espressione1; espressione2) {blocco};
----------------N.B.: istruzione1 inizializza la variabile di loop
espressione1 e' la condizione di continuazione loop (se true)
espressione2 contiene la variazione della variabile di loop
Questa istruzione 'for' equivale all'istruzione 'while' seguente:
{ istruzione1;
while (espressione1) { blocco; espressione2; }
}
5) ISTRUZIONE SWITCH:
------------------
switch (choice)
{ case1: ..... break;
case2: ..... break;
...... ecc. .......
caseN: ..... break;
default: ... break;
Si confronta il valore di
choice con i valori case1..N
ed esegue il blocco in cui
trova il true altrimenti il
default (se c'e').
<--- Opzionale
}
Si possono usare come argomenti dello switch() solo variabili di tipo
char o intere di tipo byte/short/int (escluso long).
Non si possono usare intervalli di valori.
6) BREAK CON LABEL: In genere il salto incondizionato degrada la qualita' del
---------------- programma (programmazione non strutturata) e aumenta la
probabilita' di errori. Tuttavia prevedere la possibilita'
di uscire con un salto fuori da un loop puo' essere in
certi casi vantaggioso.
Per questo Java include l'istruzione break (senza label),
che termina un loop (while,for), quando eseguita.
Esempio:
while (age<=100)
{ costo=(costo+paga)*(1+interesse);
if costo>max) break;
age++;
}
Nel caso di loop multipli annidati puo' convenire uscire
non dal singolo loop, ma dall'intero insieme dei loop
annidati: questo si puo' fare con il break con label
(equivale ad un 'goto label', che pero' non c'e' in
Java); la label (alfanumerica) etichetta l'istruzione
di loop (piu' esterno) dal quale si deve uscire.
Esempio:
read_data: while (...) <-- Label=read_data
{ ...
for (...)
{ ...
break read_data; // Esce dal while
}
}
7) GESTIONE ERRORI: Con la parola chiave 'try' si definisce un blocco
---------------- di istruzioni che puo' generare una 'exception' al
verificarsi di una condizione di 'errore'.
Se una 'exception' viene generata, un apposito blocco
di istruzioni identificato dalla parola chiave 'catch'
gestisce l'errore.
Con la parola chiave 'throws' inserita nella
dichiarazione di un metodo si pubblicizza quali
'exception' non sono gestite nel metodo ma passate
al livello piu' alto (chiamante).
La parola chiave 'throw' permette all'utente di
lanciare una 'exception' o qualunque classe che
implementa l'interfaccia 'throwable'.
Esempi di semplici programmi:
----------------------------// Esempio di uso di Radice Quadrata
class Root
{
public static void main (String arguments[])
{ int number = 100;
System.out.println("La radice quadrata di " + number
+ " e' " + Math.sqrt(number));
}
}
/*
Esempio di "if" e di passaggio di argomenti sulla riga di comando "java"
(dopo compilato con javac NewRoot, eseguire battendo: java NewRoot 100)
Mostra l'uso del parametro 100, passato al main via String[] arguments
*/
class NewRoot
{
public static void main (String[] arguments)
{ int number = 0;
if (arguments.length > 0) number = Integer.parseInt( arguments[0] );
System.out.println ("La radice quadrata di " + number
+ " e' " + Math.sqrt(number));
}
}
// Esempio di gestione errori (=Exception) con try e catch
import java.net.*; // Contiene la classe ServerSocket
import java.io.*;
public class TestTry extends Thread
{ static int Porta = 4444;
Socket theConnection;
public static void main(String[] args)
{ ServerSocket ss; // Dichiara variabile oggetto ss
try
{ ss = new ServerSocket(Porta); // Crea oggetto ServerSocket
System.out.println ("In ascolto su porta :" + ss.getLocalPort());
}
catch (IOException e)
{ System.out.println ("Errore sulla porta " + Porta + ": " + e);
System.exit (-1);
}
}
}
⌡ 14.2.10 - METODI DELLE CLASSI (=sottoprogrammi)
------------------------------------Si tratta delle subroutines (procedure e funzioni) presenti in ogni
linguaggio che qui si chiamano metodi (perche' purtroppo gli autori
del linguaggio "considerano motivo di orgoglio introdurre una nuova
terminologia per queste unita'" di programmazione).
La definizione di un metodo deve avvenire all'interno di una classe.
L'intestazione del metodo contiene le parole chiave per il controllo
dell'accesso (esempio: public static) con il tipo (esempio: int) di
variabile prodotta (=function) o void se non c'e' (=procedure) ed il
nome del metodo.
Nel primo caso (=function) il valore ritornato r viene indicato con
l'istruzione finale 'return r;'.
Esempio di applicazione in cui il metodo QuoteLotto() e' chiamato dal
metodo main (calcola la probabilita' di fare 6 (=numbers) all'enalotto
con 90 (=topNumber) numeri, cioe' calcola quote=combinazioni possibili
(=90*89*88*87*86*85/6*5*4*3*2*1)):
import InPackage.*;
public class QuoteLotto
{
// Questo e' il metodo (calcola n. di combinazioni)
public static long QuoteLotto (int high, int number)
{ long r=1; int i;
for (i=1; i<=number; i++)
{ r=r*high/i; high--;}
return r; // r=valore restituito (come long QuoteLotto)
}
// Questo e' il metodo main
public static void main(String[] args)
{ int numbers=InKeyb.leggiInt ("Quanti numeri giochi = ");
int topNumber=InKeyb.leggiInt ("Tot.numeri estraibili = ");
long quote=QuoteLotto (topNumber,numbers);// chiama metodo
System.out.println("La probabilita' e' 1 su "+quote);
}
}
Osservazioni utili:
- La sequenza sintattica prevede di scrivere prima i vari metodi ed infine
il programma principale main come segue:
public class NomeClasse
{ public static int nomeMetodo() // int e' un esempio
{ ... }
public static void main(String[] args)
{.....}
} // Terminatore della classe
- L'intestazione del metodo:
public static long QuoteLotto (int high, int number)
inizia con le parole chiave 'public static', poi il tipo di valore
restituito 'long', il nome del metodo con tipi e nomi dei parametri
passati.
Due metodi possono anche avere lo stesso nome se hanno un diverso numero
di parametri in ingresso.
- PARAMETRI PASSATI al metodo: sono sempre di tipo valore e non variabile;
quindi i metodi Java passano solo valori ma non possono modificare le
variabili, passate come parametri, nel programma chiamante, perche' gli
sono passate come copie e lui puo' modificare solo queste copie e non gli
originali). Diverso e' il caso per la variabile restituita (nell'esempio
e' QuoteLotto) che si rende disponibile per il programma chiamante.
- Il file deve avere lo stesso nome QuoteLotto.java (perche' public).
- Questo e' l'equivalente delle function del Pascal. Se non restituisce
valori si mette 'void' (invece di 'long'): in questo caso equivale alla
procedure del Pascal;
- Se mancano i parametri si deve comunque mettere le parentesi vuote ();
- Le variabili dichiarate all'interno del metodo (come 'int i') sono locali
nell'interno del blocco in cui vengono dichiarate e la relativa memoria
viene rilasciata quando si esce dal metodo;
- Esce dal metodo quando incontra 'return r'. Se non c'e' un valore
restituito r (procedure) return manca e c'e' void come tipo
nell'intestazione del metodo (al posto di 'long').
⌡ 14.2.11 - METODI DI CLASSE
---------------Rendono disponibili la funzionalita' a tutta una classe anziche' ad un solo
oggetto. Hanno 'static' nella dichiarazione. Esempio:
static void showVirusCount()
{ System.out.println("Ci sono " + virusCount + " virus.");
}
Richiamabile con:
NomeClasse.metodoStatico(parametri);
Non compare un'istanza dell'oggetto, ma il nome della classe. Quindi i
metodi di classe non possono accedere ai campi della classe che non siano
statici. Esempio:
virus.showVirusCount();
⌡ 14.2.12 - VARIABILI DI CLASSE
------------------E' possibile, anche se non consigliabile, definire delle variabili di
classe, cioe' accessibili a tutti i metodi della classe.
La sintassi e' come per le costanti di classe, cioe' vanno dichiarate
come private static subito dopo la dichiarazione di classe e prima di
ogni dichiarazione di metodo.
Esempio:
public class Employee
{ private static doublePensione = 7.62;
public static void main(String[] args)
{.....}
}
Sostituendo private con public si ottiene una vera variabile globale,
accessibile a tutti i metodi dell'applicazione.
⌡ 14.2.13 - RICORSIONE
---------Java supporta sia la ricorsione diretta che indiretta, senza particolarita'
sintattiche. Esempio di ricorsione diretta:
public static long QuoteLotto (int quote, int number)
{ if (number<=0) return 0;
else if (number==1) return quote;
else return quote*QuoteLotto (quote-1,number-1)/number
}
Il numero number decrementa ad ogni chiamata ricorsiva, garantendo cosi' che
il loop non sia infinito.
⌡ 14.2.14 - ARRAY
----In Java gli array sono oggetti.
Quindi il nome nella dichiarazione dell'array e' una variabile oggetto che
punta all'area di memoria dove sono i dati.
Si possono fare assegnazioni tra array dello stesso tipo: in tal caso pero',
se identifico due array, l'identificazione e' fatta sulle variabili-oggetto
e non sui dati, per cui dopo l'identificazione entrambe le variabili-oggetto
vengono a riferirsi alla stessa matrice di dati in memoria e non a due
matrici di dati distinte. Cio' significa che qualsiasi modifica apportata
all'una variabile si riflette anche sull'altra perche' entrambe puntano alla
stessa area dati in memoria.
Esempio di dichiarazione di un array a[] di interi [0..100]:
int[] a = new int[100];
oppure
int a[] = new int[100];
Quando gli elementi sono pochi, si puo' dichiarare e inizializzare l'array
con una sola istruzione:
int[] a = {2,3,5,7,11,13}; // Senza 'new'
Il numero di elementi di un array puo' essere ricavato con nomeArray.length()
Esempio:
for (int i=0; i<a.length(); i++)
System.out.println(a[i]);
Array multidimensionali: Esempio di dichiarazione:
-----------------------" di inizializzazione:
double[][] balance;
balance=new double[5][6];
Come per ogni oggetto, solo dopo l'inizializzazione e' possibile accedere
agli elementi balance[i][j] dell'array.
Java tratta gli array multidimensionali come array di array, cioe' come un
array monodimensionale. Questo puo' facilitare l'inizializzazione ed anche
la creazione di array frastagliati (vedasi libro per dettagli).
⌡ 14.2.15 - Passaggio di array come parametri
--------------------------------Gli array, pur essendo oggetti, sono passati come riferimenti (nascosti),
con l'indicazione del tipo di variabile.
Esempio:
public class Riordina // Dichiarazione di classe
{
// ==== Metodo ordina, con param.passato=Array a di tipo int[] ====
public static void ordina (int[] a) // Es. di array a passato come param.
{ int n = a.length();
int dj = n / 2;
while (dj >= 1)
{ for (int i=dj; i<n; i++)
{ int temp = a[i];
int j = i;
while (j>=dj && temp<a[j-dj])
{ a[j] = a[j-dj];
j -= dj;
}
a[j] = temp;
}
dj /= 2;
}
}
// ==== Metodo display (Param.passato=Array a di tipo int[] ====
public static void display (int[] a)
{ for (int i = 0; i < a.length(); i++) System.out.print(a[i] + " ");
System.out.println();
}
// ==== Metodo main ====
public static void main (String[] args)
{ int[] a = new int[10]; // make an array of ten integers
int i;
for (i = 0; i < a.length(); i++)
a[i]=(int)(Math.random()*100); // fill array (numeri a caso)
// Esempi di chiamata a metodi che non restituiscono valori (void), ma che
// modificano l'array a[] nel main.
display(a);
ordina (a);
display(a);
}
}
⌡ 14.2.16 - Esempio di I/O su disco
----------------------Al contrario delle applet, cui si impedisce normalmente di scrivere sul
disco del computer locale per ragioni di sicurezza, alle applicazioni
e' pressoche' indispensabile scrivere sul disco.
Java tratta l'I/O dei files su disco in maniera standard, come l'I/O
attraverso una connessione di rete, relegando tutte le specificita'
dell'interfacciamento con il particolare file system ad un'apposita
classe 'File'.
Anche se i dati transitano come bytes, spesso conviene rappresentarli
come strutture di livello piu' elevato, ad esempio come sequenze di
caratteri od oggetti.
In Java gli oggetti dai quali e' possibile leggere o scrivere si chiamano
'stream' di input o di output e vengono implementati a partire dalle
seguenti classi astratte:
- InputStream e OutputStream, per le sequenze di bytes;
- Reader e Writer, per le sequenze di caratteri Unicode (2 bytes).
Queste classi astratte contengono i comportamenti comuni di tutte le
sottoclassi figlie, che vengono introdotte per gestire le operazioni di
I/O in Java.
Siccome Java arriva a definire oltre 60 tipi di stream diversi (per poter
funzionare su ogni 'piattaforma'), la loro trattazione va oltre i limiti
di questo corso (per un approfondimento ci si puo' riferire al cap.12 del
testo Horstmann). Per questo motivo ci limiteremo qui' a riportare solo
due esempi di lettura e scrittura di file stream, costituiti da sequenze
di bytes su disco.
Essendo questi i casi piu' semplici, ci permetteranno di comprendere con
poca fatica gli elementi essenziali dell'I/O sui dischi in Java.
I file stream usati (FileInputStream, FileOutputStream, FileReader e
FileWriter) leggono e scrivono un file sul file system nativo del computer.
Mentre le classi di Stream si occupano dei contenuti dei files, la classe
'File' si occupa dell'interfacciamento di Java con il file system locale
(fornendo cosi' l'indipendenza dalla piattaforma per tutto il resto del
codice Java) e consente la gestione completa dei files su disco, tramite
metodi che permettono di eseguire anche i vari comandi, quali delete,
rename, ecc. (vedi le API di java.io.File).
Il seguente programma (FileTest.java) usa la classe FileWriter per scrivere
dei dati sul file FileTest.txt:
// ==== Esempio di scrittura su disco ====
import java.io.*;
public class FileTest
{
public static void main (String[] args) throws IOException
{
/* Creo l'oggetto FileWriter (specifiche del file system locale),
assegnandogli l'handle outFile */
FileWriter outFile = new FileWriter ("FileTest.txt");
/*
Usando i dati dell'oggetto outFile, creo l'oggetto PrintWriter
(flusso Java), referenziato con la variabile oggetto 'out' */
PrintWriter out= new PrintWriter (outFile);
// Esegue scrittura su disco
String testo="I re di Roma sono ";
int giorni=7;
out.print (testo);
// Analoga a System.out.print()
out.println (giorni); // Idem ...
// Chiusura dell'oggetto PrintWriter (recupera memoria)
out.close();
}
}
Questo codice crea un oggetto outFile, che rappresenta il file FileTest.txt
sul file system locale del computer (File e' una utility class contenuta in
java.io).
Il programma apre un FileWriter su FileTest.txt. Poi scrive i dati sul
writer 'out' (istanza di PrintWriter), chiudendo il writer alla fine.
Il codice usato per creare il file writer (equivalente ad una 'open') e'
il seguente:
FileWriter outFile=new FileWriter("FileTest.txt");//Link a file system locale
PrintWriter out = new PrintWriter (outFile);// Gestione standard flusso Java
compattabili anche in un'unica istruzione:
PrintWriter out = new PrintWriter (new FileWriter ("FileTest.txt"));
Con PrintWriter si possono usare gli stessi metodi print e println, usati
con System.out, per stampare numeri, boolean, caratteri, stringhe e oggetti.
Le classi FileReader e FileWriter leggono e scrivono caratteri di 16-bit.
Quello che segue un programma analogo al precedente, ma per un computer con
file system nativo che lavora invece con caratteri di 8-bit.
Esso usa le classi FileInputStream and FileOutputStream invece di FileReader
e FileWriter (anche questo programma e' sul dischetto delle esercitazioni)
per copiare il contenuto del file FileCopy.java nel nuovo file FileCopy.txt:
// ==== Esempio di I/O su Disco (Copia un text file, byte per byte) ====
import java.io.*;
public class FileCopy
{
public static void main (String[] args) throws IOException
{
/* Prima definisco due oggetti File (specifici del file system
locale), assegnando loro gli handles inputFile e outFile */
File inputFile = new File ("FileCopy.java");
File outputFile= new File ("FileCopy.txt");
/*
Poi, usando i dati degli oggetti inputFile e outputFile, creo
gli oggetti FileInputStream e FileOutputStream (flussi Java),
che saranno referenziati con le variabili oggetto in e out
FileInputStream in = new FileInputStream (inputFile);
FileOutputStream out= new FileOutputStream (outputFile);
*/
/*
Ora leggo su 'in', carattere per carattere come interi (ASC),
e riscrivo su out (fino all'end-of-file) */
int c;
while ((c=in.read()) != -1)
{
// System.out.println(c); // Istruzione di test (per vedere cosa fa)
out.write(c);
}
in.close(); // Chiusura dei flussi FileInputStream e FileOutputStream
out.close();
}
}
Il programma apre un FileInputStream sul file FileCopy.java del file
system locale ed un FileOutputStream sul file FileCopy.txt.
Poi legge caratteri dal reader (in) e li scrive sul writer (out), chiudendo
reader e writer alla fine.
Il codice usato per creare il file reader (equivalente ad una 'open') e'
in questo caso:
File inputFile = new File ("FileCopy.java"); // Link a file system locale
FileInputStream in=new FileInputStream(inputFile);// Gestione standard flusso
La classe File (una utility class contenuta in java.io) contiene le
funzionalita' necessarie per connettersi al file system del computer locale,
mentre le classi di Stream si occupano dei contenuti del file (gestione
standard Java dei flussi).
Questo codice crea un oggetto File, che rappresenta il file FileCopy.java,
presente sul file system locale del computer.
!----------------------------------------------------------------------⌡ 14.3 - PROGRAMMAZIONE 'ORIENTATA AD OGGETTI' (OOP)
===========================================
⌡ 14.3.1 - Introduzione
-----------JAVA e' un linguaggio totalmente ad oggetti, per cui conviene capire
subito cosa cio' significa.
Il processo che ha portato allo sviluppo nell'ingegneria del software della
programmazione orientata ad oggetti e' simile a quello avvenuto nel campo
dell'hardware: un costruttore di PC originariamente era costretto a
progettare e costruire i vari componenti (meccanica, alimentatore, scheda
madre, ecc.), poi si e' accorto che era piu' conveniente trasformare ove
possibile il lavoro di costruttore in quello di assemblatore, lasciando
ad altre societa', specializzate nella costruzione dei singoli componenti,
il lavoro della loro costruzione (per esempio l'alimentatore risulta
costruito meglio ed a costi piu' bassi da un costruttore specializzato di
Singapore, la scheda madre da un costruttore di Taiwan, ecc.).
In generale si puo' osservare che l'esigenza di progredire ha portato alla
necessita' della modularizzazione, nel campo dell'hardware ma anche in
quello del software, per poter fornire sistemi composti da componenti
sempre piu' complessi a costi sempre piu' bassi.
Nel campo del software la progressiva crescita della dimensione dei programmi
(applicazioni), dagli anni settanta in poi, ha portato alla ricerca della
modularizzazione e dell'indipendenza dei moduli, sia per facilitare la
progettazione ed il debugging, che per rendere piu' agevole la suddivisione
del lavoro ed il coordinamento tra piu' persone impegnate nello stesso
progetto.
Il lavoro di gruppo e la documentazione del progetto sono facilitati da
metodologie che lo rappresentano con diagrammi, come quelli prodotti con
UML, Universal Modeling Language (www.rational.com/uml/index.html), per
esempio con il tool Together/J, che mostra la corrispondenza tra elementi
del diagramma del progetto ed il codice Java).
Queste metodologie si appoggiano sulle tre relazioni essenziali tra le
classi di un progetto: Uso, Contenimento e Ereditarieta' (spiegate piu'
avanti).
La Programmazione Orientata ad Oggetti (OOP) ha sostituito le tecniche di
programmazione strutturata, che consistevano nell'individuazione delle
procedure (algoritmi) necessarie per elaborare i dati globali e loro
successiva scrittura in istruzioni elementari.
Nella programmazione strutturata procedurale la struttura dei dati veniva
scelta alla fine, in modo da agevolare la programmazione delle procedure.
La OOP ha invertito questo ordine, dando la precedenza alla struttura dei
dati e lasciando in secondo ordine gli algoritmi che agiscono sui dati.
La scrittura di programmi strutturati, suddivisi in moduli che comunicano tra
loro tramite chiamate di procedure e non mediante condivisione di dati, ha
costituito la base per la nascita della programmazione orientata ad oggetti.
Questa non risolve pero' soltanto il problema della modularizzazione di
grandi applicazioni (presentando, per esempio, invece di 2000 procedure
per l'esecuzione di 2000 funzioni, solo 100 classi con una media di 20
metodi per classe), ma consente anche in modo naturale di impiegare i
metodi (procedure) contenuti in una classe (modulo) su piu' blocchi di
dati diversi (dati oggetto) contemporaneamente: infatti una volta definita
una classe si puo' lavorare con un numero qualsiasi di istanze di quella
classe (invece nella programmazione procedurale normalmente un modulo ha
una sola istanza). Cio' significa che la OOP risolve automaticamente in
maniera nativa i problemi di utilizzo di una sola copia del codice macchina
(con i problemi di rientranza risolti a monte da compilatore e interprete
VM), della salvaguardia (in aree di memoria diverse per ogni istanza) delle
variabili locali e dei parametri passati delle varie istanze.
Cio' e' proprio quello che serve per poter operare in multitasking.
Quindi Java, essendo un linguaggio OOP, supporta l'elaborazione simultanea
di piu' task (chiamati 'thread'), i quali possono lavorare su diverse
istanze dello stesso oggetto, caricate in posizioni diverse della memoria.
Inoltre nel lavoro di gruppo non si deve permettere, a titolo di esempio,
che altri programmatori, all'insaputa dell'autore, possano accedere ad un
modulo di programma (classe), derivandone altri che accedono ai campi dei
dati, perche' cosi' si avrebbe come conseguenza, che se l'autore apporta
dei cambiamenti alla sua classe puo' sconvolgere la funzionalita' delle
applicazioni degli altri programmatori che, a sua insaputa, stanno usando
la sua classe.
Queste problematiche portano a concepire l'incapsulamento dei dati ed
il controllo dell'accesso, che sono caratteristiche fondamentali della
programmazione ad oggetti e quindi di Java.
Alla fine del paragrafo 14.3.5 elencheremo gli accorgimenti che in Java si
possono adottare per raggiungere questi obiettivi.
⌡ 14.3.2 - Modo di lavorare in JAVA
-----------------------In JAVA si programmano le classi, che contengono i metodi (sottoprogrammi).
Con questi si definiscono gli oggetti con cui si lavora (metodi costruttori),
cioe' si creano gli oggetti (istanze della classe) tramite le istruzioni
'new', ognuno identificato dalla sua variabile oggetto (=nome).
Poi gli si attribuisce lo stato iniziale e quindi si lavora con gli oggetti
(referenziati con il nome della variabile oggetto), mediante chiamate ai
metodi delle classi.
Queste chiamate differiscono dalle chiamate ai sottoprogrammi della
programmazione procedurale (generalizzazione): per esempio un oggetto non
dovrebbe mai manipolare direttamente i dati interni di un altro oggetto.
Queste elaborazioni possono avvenire invece tramite 'chiamate ai metodi'
dell'altro oggetto, ovvero
GLI OGGETTI CLIENT DEVONO INVIARE MESSAGGI AGLI OGGETTI SERVER
che si incaricano di manipolare i dati internamente alla loro classe.
In questo modo si tutela la possibilita' di riutilizzo (rientranza), si
riduce la dipendenza dai dati e si facilita il debugging.
Le librerie standard di Java mettono a disposizione migliaia di classi
per i piu' vari scopi: interfacce grafiche per l'utente, programmazione
in rete, ecc.
Il lavoro del programmatore e' quello di creare classi personali per
creare ed elaborare oggetti necessari all'applicazione, usando le classi
disponibili nelle librerie standard utili per l'applicazione.
Esempio:
se ho una classe AudioClip, posso applicare i metodi di AudioClip agli
oggetti del tipo AudioClip, identificati dalle rispettive variabili oggetto
che posso definire cosi':
AudioClip miao; // Definizione della variabile oggetto miao di tipo AudioClip
(ma non dell'oggetto: finche' non viene creato l'oggetto
associato, non si puo' applicare nessun metodo a miao,
cioe' l'istruzione miao.play(); darebbe errore run-time).
L'oggetto associato si crea con l'operatore 'new' cosi':
miao=new AudioClip(); // Crea un nuovo oggetto (istanza della classe
AudioClip), collegato alla variabile oggetto 'miao'
cioe' alloca la memoria per i campi dell'oggetto.
Queste due possono anche essere integrate in una sola istruzione (che crea
l'oggetto miao) come segue:
AudioClip miao = new AudioClip();
Altri esempi di uso (gia' incontrati):
CREAZIONE DELL'OGGETTO 'Cocker' della classe 'Cane':
ASSEGNAZIONE DEGLI ATTRIBUTI all'oggetto 'Cocker' :
RICHIAMO DEL METODO 'parla' dell'oggetto 'Cocker' :
RICHIAMO DELLA VARIABILE 'nome' dell'ogg. 'Cocker' :
(richiamabile se non e' private).
Cane Cocker=new Cane();
Cocker.name="Chicca";
Cocker.parla();
... Cocker.name ...
⌡ 14.3.3 - Uso delle classi esistenti
-------------------------Importanti sono i metodi che una classe mette a disposizione per eseguire
i vari compiti sui suoi oggetti. Essi risultano nella documentazione API
(Application Programming Interface) della classe.
Sul libro e' riportato l'esempio di uso della classe API corejava.Day,
disponibile in un package didattico del libro, chiamato corejava (che
deve risultare accessibile con la CLASSPATH impostata nel vostro computer).
La classe portata come esempio, Calendar.java, dopo compilazione con
javac Calendar.java
se eseguita con
java Calendar 12 1999
visualizza il calendario di dicembre 1999.
Per i metodi usati ci si e' riferiti alle note API della classe corejava.Day
elencate a pag.113 del testo (copyright riservato del libro).
import corejava.*; // Contiene la biblioteca con Day.class
public class Calendario
{ public static void main(String[] args)
{ int m; int y;
if (args.length() == 2)
{ m = Integer.parseInt(args[0]); // m,y passati all'avvio con java
y = Integer.parseInt(args[1]);
}
else
{ Day oggi = new Day(); // Ricava m,y dalla data di oggi
m = oggi.getMonth();
y = oggi.getYear();
}
//
..........ecc.........
System.out.println(m + " " + y);
}
}
⌡ 14.3.4 - Uso delle classi personali
-------------------------Consideriamo come esempio tipico di programmazione ad oggetti quello della
classe Employee sotto riportata.
La classe deve contenere:
- la dichiarazione dei campi contenuti all'interno delle varie istanze della
classe Employee (nell'esempio: String nome e double salario);
- un metodo (detto 'costruttore'), con lo stesso nome (Employee) della
classe, usato per creare ed inizializzare gli oggetti della classe
(assegnando alle variabili dei vari campi i valori iniziali voluti).
Il metodo costruttore dev'essere sempre chiamato con la parola chiave
'new' e non restituisce valori (nell'esempio: il metodo Employee);
- i metodi pubblici che mette a disposizione delle altre classi per
l'accesso e modifica dei campi delle varie istanze create con i propri
costruttori. Questi sono in genere gli unici modi di accesso a quegli
oggetti (incapsulati; nell'esempio i metodi display e incremSalario),
poiche' gli altri metodi dell'utente, esterni alla classe, non possono
mai modificare quegli oggetti in quanto scambiano i parametri solo di
tipo valore e non per riferimento (vedi piu' sotto).
Se il modificatore dell'accesso e' private l'accesso e' ristretto alla
classe mentre se non e' specificato l'accesso e' consentito a tutti
i metodi dello stesso package (insieme di classi raggruppate con
l'intestazione 'package nomePackage;' all'inizio del file).
La classe mette a disposizione gli entry point dei vari metodi ma non ha
un punto di inizio dell'esecuzione del programma.
Per questo aggiungiamo la classe EmployeeTest per provare il programma.
// ==== Programma per il test della classe Employee ====
import java.util.*;
public class EmployeeTest
{ public static void main (String[] args)
{ Employee[] staff = new Employee[3];
staff[0] = new Employee ("Tizio", 45000);
staff[1] = new Employee ("Caio", 65000);
staff[2] = new Employee ("Sempronio" , 58000);
int i;
for (i=0; i<3; i++) staff[i].incremSalario(5); //Modif.delegata al metodo
for (i=0; i<3; i++) staff[i].display();
}
}
class Employee // Inizio della classe Employee
//Tutti metodi pubblici per renderli accessibili da altre classi
{ public Employee (String n, double s) //Metodo costruttore di oggetti
{ nome = n;
salario = s;
}
public void display()
{ System.out.println (nome + " " + salario);
}
public void incremSalario (double percento)
{ salario = 1 + percento / 100;
}
// Tutti campi delle 2 istanze sono 'private' per impedire l'accesso esterno:
// campi manipolabili solo dai metodi della classe Employee (incapsulamento),
// cosi' in caso di errore si limita il debugging all'interno della classe.
private String nome;
private double salario;
}
⌡ 14.3.5 - Passaggio di oggetti come parametri
----------------------------------Anche le variabili oggetto, pur essendo riferimenti come i nomi degli
array, non sono passate per riferimento, ma sono usate per creare una
copia dell'oggetto originale, su cui far operare le istruzioni del metodo.
Quindi in Java anche gli oggetti, come i tipi standard (numeri, ecc.), sono
sempre passati come valori e non come riferimenti: cioe' il metodo lavora
con una copia del dato passato e non con l'indirizzo del dato originale.
Come conseguenza, i metodi non possono mai ritornare variati i valori dei
parametri scambiati.
Per esempio se in un main si chiama il seguente metodo swap(c,d), non si
ottiene lo scambio dei due oggetti c e d:
static void swap (String a, String b) // Non funziona!
{ String temp = b;
b = a;
a = temp;
}
L'unica eccezione e' quella degli array, gia' discussa in precedenza
(vedi gli esempi Riordina.java e SwapTest.java).
Questa e' una situazione che puo' apparire scomoda perche' riduce la
liberta' del programmatore, ma il modo di lavorare che si impone cosi'
va nella direzione di produrre codici di programma, in cui gli errori
sono meno frequenti e piu' localizzati.
Basta in definitiva attenersi alle seguenti regole canoniche della
programmazione ad oggetti:
1) Usare sempre dati 'privati': questo garantisce l'incapsulamento e
confina i problemi di programmazione all'interno della classe
(facilita' di debug e quindi possibilita' di gestire anche programmi
molto grandi).
2) Conseguentemente, prevedere nella classe tutti i metodi di accesso e
di modifica dei campi dell'oggetto necessari agli utenti esterni alla
classe (essi saranno l'unico modo di accesso dall'esterno).
3) Quando si deve accedere o modificare oggetti di un'altra classe farlo
solo con chiamate ai metodi di quella classe.
4) Anche se la maggior parte dei metodi che si incontrano e' di tipo
'public', e' opportuno realizzarne il piu' possibile di tipo 'private'
(di uso esclusivo locale all'interno della classe), magari suddividendo
i metodi grandi in piu' piccoli, alcuni dei quali possono risultare
'private'.
Un metodo 'public' puo' sempre essere usato da altre classi e quindi
non puo' essere eliminato o modificato con la stessa tranquillita' di
un metodo 'private'.
⌡ 14.3.6 - Progettazione nella programmazione a oggetti
-------------------------------------------Per risolvere un problema applicativo con la programmazione a oggetti
occorre individuare le classi ed i relativi metodi da programmare.
In genere nell'analisi di un problema i sostantivi corrispondono alle
classi ed i verbi ai metodi.
Consideriamo per esempio un sistema di gestione degli ordini. In esso
le classi corrispondono ai sostantivi ARTICOLO, ORDINE, ORDINE.URGENTE,
CONTO.
Le varie istanze di queste classi (create con 'new') sono i dati su cui
operano i metodi.
Esempi di metodi della classe ORDINE (corrispondenti ai verbi) sono:
- 'aggiungi', 'togli' ARTICOLO in un ORDINE
- 'scarica' un ORDINE in CONTO
⌡ 14.3.7 - Relazioni tra le classi
----------------------- Uso: una classe A usa una classe B se ne chiama i metodi (tramite scambio
di messaggi) o se ne manipola gli oggetti (cioe' crea, riceve o
restituisce oggetti della classe B).
Per esempio la classe ORDINE usa la classe CONTO in quanto gli oggetti
di ORDINE (di un cliente) devono accedere agli oggetti del CONTO (di
quel cliente) per controllare il credito.
La classe ARTICOLO invece non usa la classe CONTO perche' i suoi
oggetti per andare in un ORDINE non hanno bisogno di manipolare gli
oggetti del CONTO del cliente.
- Contenimento: e' un caso speciale di uso. Esempio: un oggetto ORDINE
contiene oggetti ARTICOLO
- Ereditarieta': corrisponde a specializzazione. La classe ORDINE.URGENTE
eredita i metodi della classe ORDINE (per esempio: aggiunta di
articoli in ORDINE, scaricamento di un ORDINE sul CONTO di un
cliente, ecc.), ma ha anche ulteriori suoi metodi speciali (per
gestire le priorita', per aggiungere i supplementi di costo, ecc.).
Queste relazioni sono alla base della progettazione orientata agli oggetti,
che si avvale di diagrammi in cui le classi corrispondono ai riquadri e le
relazioni alle linee (diverse per le tre relazioni).
Esempio di diagramma delle classi (notazione UML = Universal Modeling
Language):
┌────────────────┐
CLASSI ---->
│ ORDINE.URGENTE │
└───────╦────────┘
RELAZIONI --->
Ereditarieta'║
┌───╩────┐
Uso
┌─────────┐
│ ORDINE ├--─-─-─-─>│ CONTO │
└───┬────┘
└─────────┘
Contenimento │
┌────┴─────┐
│ ARTICOLO │
└──────────┘
⌡ 14.4 - EREDITARIETA'
=============
⌡ 14.4.1 - Introduzione
-----------Gli oggetti corrispondono a blocchi di dati relativi ad entita' soggette alla
elaborazione come: eventi sperimentali, prenotazioni, impiegati, ecc.
Ognuna di queste entita' ha bisogno di piu' dati per essere completamente
descritta e in Java questi dati vengono definiti nel metodo costruttore, che
alloca loro la memoria, ed elaborati con i metodi della classe appositamente
predisposti.
Talvolta a queste entita' esistenti se ne vengono ad aggiungere altre simili
ma piu' specializzate, nel senso che ai campi gia' esistenti se ne aggiungono
altri per descriverle. Per esempio i dirigenti di un'azienda sono anch'essi
impiegati e quindi il metodo costruttore di una classe (Manager) che li
rappresenta conterra' gli stessi campi dell'impiegato (Employee), piu'
qualche altro (per esempio la funzione direttiva).
In questi casi, in cui l'intersezione insiemistica dei campi degli oggetti
delle due classi non e' vuota, e' possibile creare la nuova classe Manager,
utilizzando quanto gia' programmato per la classe Employee con la tecnica
dell'ereditarieta' nel modo seguente:
class Manager extends Employee // <--- parola chiave 'extends'
{ public Manager (String n,double s)
{ super (n,s);
// super = chiama costruttore Employee
headFunction=""; // campo aggiuntivo (inizializzaz.)
}
public String getHeadFunction()
{ return headFunction;
}
public void setHeadFunction(String name)
{ headFunction=name;
}
private String headFunction;
}
La classe preesistente Employee si chiama superclasse.
Tutti i metodi della superclasse sono disponibili alla classe figlia, per
cui in questa si programmano solo le differenze e le aggiunte.
Tutte le funzionalita' comuni alle due classi saranno quindi programmate
nella superclasse.
Discendenza delle classi: essendo le classi rientranti possono essere
richiamate nella definizione di nuove classi in 'estensione' delle
precedenti (inheritance hierarchy) con lo statement 'extends' nella
dichiarazione di classe.
Esempio:
/* ==== Esempio di definiz.di oggetti con ereditarieta' ====
* ...Uomo extends Dormiente... significa che dalla
* superclasse Dormiente (madre) deriviamo la sottoclasse Uomo
* (figlia) ---> Ogni Uomo e' un Dormiente
* N.B. I metodi potrebbero anche essere compilati separatamente
* La routine con metodo 'dorme' e' comune a Cane e Uomo
* (scritta una sola volta)
*/
class Parla
{
// --- Classe (madre) degli oggetti Dormiente --public static class Dormiente
{ String name;
public static void dorme() // <--- metodo dorme (comune a Cane e Uomo)
{ System.out.println ("zzzzzzzzzzzzzz");
}
}
// --- Classe (figlia) degli oggetti 'Cane' con metodo 'parla'--public static class Cane extends Dormiente
{ public static void parla() // <--- Metodo parla di Cane
{ System.out.println("Bau! Bau!");
}
}
// --- Classe (figlia) degli oggetti 'Uomo' con metodo 'parla'--public static class Uomo extends Dormiente
{ public void parla() // <--- Metodo parla di Uomo
{ System.out.println("Nel mezzo del cammin di nostra vita....");
}
}
// --- Programma principale --public static void main (String arguments[])
{ // --- Definiz.oggetti Cocker e Studente --Cane Cocker = new Cane();
Uomo Studente=new Uomo();
// --- Assegnazioni attributo name --Cocker.name = "Chicca";
Studente.name = "Mario";
// --- Inizio esecuzione --System.out.println ("Ora parla " + Studente.name + ":");
Studente.parla();
System.out.println ("Ora parla " + Cocker.name + ":");
Cocker.parla();
System.out.println ("Ora dormono entrambi:");
Cocker.dorme();
Studente.dorme();
}
} // Fine della classe
Output prodotto dall'esecuzione del main:
"Ora parla Mario:"
"Nel mezzo del cammin...."
"Ora parla Chicca:"
"Bau! Bau!"
"Ora dormono entrambi:"
"zzzzzzzzzzzzzz"
"zzzzzzzzzzzzzz"
⌡ 14.4.2 - Gerarchie dell'ereditarieta'
---------------------------La tecnica dell'ereditarieta' si puo' estendere a piu' livelli gerarchici.
Per esempio la classe Manager, figlia di Employee, puo' a sua volta essere
padre di una classe ancora piu' specializzata (quella dei Dirigenti)
ed altre classi specializzate di impiegati possono essere quelle degli
operai e delle segretarie (che non avrebbero nulla in comune con la classe
Manager).
Questa situazione e' rappresentata nel diagramma seguente:
EREDITARIETA':
┌───────────────────────────┐
SUPERCLASSE ---->
│
Employee
│
└─╦───────────╦───────────╦─┘
║
║
║
┌───╩───┐ ┌────╩─────┐ ┌──╩────┐
CLASSI FIGLIE ---> │Manager│ │Segretaria│ │Operaio│
└───┬───┘ └──────────┘ └───────┘
┌────┴────┐
│Dirigente│
└─────────┘
Per un uso appropriato dell'ereditarieta' bisognerebbe individuare tutte le
operazioni ed i campi comuni a piu' classi e spostarli piu' in alto lungo
l'albero, evitando cosi' duplicazioni di definizioni e di metodi, che sono
molto pericolose quando si riferiscono alle stesse entita', perche' anche
correzioni e modifiche future vanno applicate in piu' punti del programma
(anziche' in un solo punto: nella superclasse).
Si puo' anche impedire ad una classe di diventare superclasse, mettendo
il modificatore 'final' nella definizione di classe (puo' convenire per
velocizzare l'elaborazione eliminando la ricerca lungo la gerarchia dei
metodi chiamati: binding dinamico).
Esempio:
final class Employee
{ .....
}
Gli oggetti delle classi figlie (Manager) hanno in genere piu' campi
(NomeSegretaria) degli oggetti della superclasse (Employee), per cui puo'
essere necessario convertire il tipo di un oggetto.
Questo si puo' fare con un processo chiamato 'cast' che e' analogo a quello
visto per la conversione dei tipi di variabili standard.
Esempio di cast:
Manager boss = (Manager) staff[0];
dove staff[0] e' un'istanza di Employee.
Ovviamente il cast e' permesso solo dentro lo stesso albero di gerarchia di
ereditarieta'.
E' anche disponibile un operatore 'instanceof' per verificare la classe
di un oggetto prima di applicare un cast, al fine di evitare 'eccezioni'
runtime. Esempio:
if (staff[0] instanceof Manager)
{ boss = (Manager) staff[0];
.............
}
Funzionalita' utili a tutte le classi sono definite in una superclasse
cosmica implicita, radice di tutte le classi, chiamata Object.
Per la descrizione dei metodi messi a disposizione (boolean equals(),
Object clone(), String toString(), ecc.) vedere le note API (sul testo
o in rete).
⌡ 14.4.3 - Controllo dell'accesso
---------------------Le parole chiave (modificatori di accesso) che controllano l'accesso a campi
e metodi delle classi sono tre e funzionano nel modo seguente (in ordine di
restrizione decrescente):
1) 'private' : accesso
2) senza modificatore:
3)'protected': accesso
4) 'public' : accesso
consentito solo entro la stessa classe;
accesso consentito al package.
consentito al package e a tutte le sottoclassi figlie;
consentito a tutti;
Nella programmazione ad oggetti si devono privilegiare le scelte che
favoriscono l'incapsulamento (cioe' accesso 'private'), per i motivi gia'
detti in precedenza.
Si puo' rinunciare all'incapsulamento per ottenere maggiore flessibilita'
e funzionalita', ma si dev'essere coscienti che si acquisiscono dei rischi.
Anche l'accesso protected viola l'incapsulamento perche' puo' permettere,
per esempio, ai metodi di Manager (figlio) di accedere ad un oggetto di
Employee (padre), se questo e' definito come protected anziche' private.
Per capire l'importanza di usare bene il controllo dell'accesso, supponiamo
che Employee abbia i suoi campi definiti 'protected'; allora altri
programmatori possono, all'insaputa dell'autore della classe Employee,
accedere alla classe derivandone altre classi che accedono ai suoi campi
protetti.
Questo compromette l'incapsulamento e porta come conseguenza, a titolo di
esempio, che se l'autore di Employee apporta dei cambiamenti alla sua
classe puo' sconvolgere la funzionalita' delle applicazioni degli altri
programmatori che, a sua insaputa, stanno usando la sua classe, poiche'
l'accesso protected glielo consente.
⌡ 14.4.4 - Polimorfismo
-----------Nella programmazione ad oggetti l'elaborazione procede inviando richieste
(messaggi) di esecuzione di metodi agli oggetti con determinati parametri.
L'oggetto, sottoclasse della sua gerarchia di ereditarieta', verifica se
possiede il metodo con quel nome e con l'esatto elenco di parametri passati
(che costituiscono la 'segnatura' o firma del metodo). In caso affermativo
lo esegue, altrimenti PASSA LA RICHIESTA ALLA CLASSE PADRE.
In questo modo la richiesta risale l'albero gerarchico verso le classi
antenate, finche' non trova una corrispondenza (se non la trova si genera
un errore in fase run-time).
Possono coesistere, in classi diverse della gerarchia dell'ereditarieta',
anche metodi con lo stesso nome e addirittura con gli stessi parametri:
in tal caso il meccanismo descritto rende visibile solo il primo metodo
con la giusta firma, che si incontra risalendo la gerarchia (gli altri
nelle classi genitrici risultano nascosti).
Questo meccanismo, con cui un oggetto risulta in grado di decidere quale
metodo applicare, si chiama polimorfismo.
La funzionalita' risultante e' che oggetti, ovvero sottoclassi diverse,
nella catena dell'ereditarieta' possono rispondere in maniera diversa
allo stesso messaggio (che e' la richiesta di esecuzione di un metodo).
Il meccanismo tradizionale di chiamata di un metodo (binding statico o
early binding) permette di definire completamente l'operazione in fase
di compilazione del programma.
Con il polimorfismo invece il compilatore genera il codice con cui poter
determinare dinamicamente, in fase run-time, quale metodo eseguire,
utilizzando le informazioni disponibili sull'oggetto (binding dinamico
o late binding).
In conclusione possiamo dire che ereditarieta' e polimorfismo determinano
il modo di comportarsi degli oggetti: essi acquisiscono la capacita' di
sapere come svolgere il loro lavoro, potendo anche evolvere dinamicamente
il loro comportamento.
⌡ 14.5 - INTERFACCIA GRAFICA (GUI)
=========================
⌡ 14.5.1 - Apertura di una finestra
-----------------------L'uso delle GUI (Graphical User Interface) e' reso molto semplice negli
ambienti di sviluppo di applicazioni come Visual Basic, Visual C++ ,
Delphi, Forte', ecc., che mettono a disposizione del programmatore i
necessari strumenti grafici di layout e gli editor di risorse; con essi si
impostano le caratteristiche grafiche ed il sistema genera automaticamente
il codice di programmazione GUI corrispondente.
Senza usare tali sistemi di sviluppo e per comprendere la programmazione
grafica GUI, diamo ora alcune informazioni di base al riguardo.
Gia' nella versione 1.1, Java conteneva una libreria di classi AWT (Abstract
Window Toolkit) per la programmazione dell'interfaccia grafica (GUI).
Dal 1996 Netscape e Sun hanno collaborato per la creazione di una nuova
libreria di interfacce utente GUI denominata Swing, che e' stata inclusa
nel JFC (Java Foundation Classes, una libreria piu' ampia contenente, per
esempio, anche le API di accessibilita' e le API per il drag-and-drop).
Le classi Swing per l'interfaccia grafica GUI sono contenute nel package
javax.swing.
Mostriamone l'uso con l'esempio seguente, in cui definiamo una prima classe
EsempioFrame che si comporta come la JFrame di Swing, eccetto per il titolo
e le dimensioni (definite con setTitle e setSize).
La seconda classe FrameTest, con il metodo main, crea l'oggetto frame (cioe'
una finestra top-level, non contenuta in altre) con una chiamata a new e lo
mostra su video con il metodo show nella posizione di default, che e' in alto
a sinistra (si potrebbe anche posizionare altrove sullo schermo la finestra
frame con il metodo setLocation).
// ---- Crea un frame e lo mostra su video ---import javax.swing.*;
class EsempioFrame extends JFrame
// Definisce EsempioFrame con titolo e ampiezza
{ public EsempioFrame ()
{ setTitle("EsempioFrame");
setSize(300,200);
}
}
// Crea oggetto frame e lo mostra (in alto a sinistra)
public class FrameTest
{ public static void main(String[]args)
{ JFrame frame=new EsempioFrame();
frame.show();
}
}
Invece di usare due classi distinte (con due files .class generati),
potremmo fare tutto nella stessa classe EsempioFrame con due metodi
EsempioFrame e main nel modo seguente:
public class EsempioFrame extends JFrame
{ public EsempioFrame ()
{ setTitle("EsempioFrame");
setSize(300,200);
}
public static void main (String[]args)
{ JFrame frame=new EsempioFrame();
frame.show();
}
}
Un problema che si presenta con i frame e' che la visualizzazione della
finestra attiva un thread di interfaccia-utente, che rimane attivo anche
dopo il termine del metodo main.
Per chiudere il thread (cioe' per riottenere il prompt dopo l'esecuzione
di 'java EsempioFrame' nella shell DOS di esecuzione del JDK) sono
necessarie numerose istruzioni, che passano l'ordine della terminazione
del thread del frame al programma chiamante 'java' per poterne eseguire
la chiusura. Esse sono raccolte nell'apposito metodo, che riportiamo
nell'esempio seguente (CloseTest.java), rimandando al testo per ulteriori
dettagli:
import java.awt.event.*;
import javax.swing.*;
// --- Definisce CloseFrame con titolo, ampiezza e posizione --class CloseFrame extends JFrame
{ public CloseFrame ()
{ setTitle("CloseFrame");
setSize(300,200);
//
L'istruzione seguente termina il thread per la chiusura del frame
addWindowListener(new WindowAdapter()
{ public void windowClosing(WindowEvent e) { System.exit(0); } });
}
}
// --- Crea oggetto frame e lo mostra in alto a sinistra --public class CloseTest
{ public static void main(String[]args)
{ JFrame frame=new CloseFrame();
frame.show();
}
}
⌡ 14.5.2 - Metodi per gestire i frame
-------------------------Nella classe JFrame sono contenuti vari metodi, che consentono di operare
con i frame, cioe' con le finestre top-level, non contenute in altre.
Ne elenchiamo i principali:
- Metodo 'dispose'
: chiude la finestra e ne recupera le risorse
impegnate;
- Metodo 'setIconImage': imposta immagine da usare quando la finestra e'
ridotta ad icona;
- Metodo 'setTitle'
: modifica il testo nella barra del titolo;
- Metodo 'setResizable': imposta valore boolean per ridimensionamento frame;
Altri metodi sono indicati nelle note API java.awt.Component sul testo
(la classe Component, nella catena di ereditarieta' della classe JFrame,
e' l'avvio di tutti gli oggetti GUI).
In Java un frame e' un contenitore di componenti grafici (GUI), mentre i
disegni vengono normalmente eseguiti su un componente (realizzato con la
classe JPanel) chiamato 'pannello del contenuto', che viene inserito nel
frame.
La struttura interna di un JFrame e' la seguente (gli altri pannelli servono
per usi particolari come: barra dei menu', ambientazione, ecc.):
╔═════════════════════════════════════════════╗
║ █ TITOLO
█ █ █ ║
╠═════════════════════════════════════════════╣
║
JFrame
║
┌─────────────────────────────────────────────┐
║
│
JRoot
│
║
┌─────────────────────────────────────────────┐
│
║
│
JLayeredPane
│
│
║
┌─────────────────────────────────────────────┐
│
│
║
│ Pannello del contenuto (+barra dei menu') │
│
│
║
┌─────────────────────────────────────────────┐
│
│
│
║
│
Pannello 'di vetro'
│
│
│
│
║
│
│
│
│
│
║
│
│
│
│
│
║
│
│
│
│
│═══╝
│
│
│
│
│
│
│
│
│───┘
│
│
│
│
│
│
│───┘
│
│
│
│
│───┘
│
│
└─────────────────────────────────────────────┘
Si puo' aggiungere un pannello in un frame con le istruzioni seguenti:
import javax.swing.*
.....................
Container ContentPane = frame.getContentPane ();
JPanel pannello = new JPanel();
ContentPane.add (pannello);
Per disegnare nel pannello occorre :
1) Definire una classe che estende JPanel;
2) Usare il metodo paintComponent per disegnare l'oggetto grafico.
In questa sede non possiamo addentrarci ulteriormente nell'argomento, per
cui invitiamo il lettore a riferirsi al testo per ulteriori informazioni.
⌡ 14.5.3 - Metodi per disegnare i testi
---------------------------I testi sono considerati disegni particolari e quindi, come oggetti di tipo
Graphics, possono essere disegnati con il metodo:
gr.drawString(text,xCoord,yCoord)
Un esempio e' il programma TestMioFrame.java, che scrive un testo nel
pannello nel modo seguente:
// --- Esempio di classe che scrive (=disegna) un testo --import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
class MioFrame extends JFrame // Definisce classe MioFrame
{ public MioFrame ()
{ setTitle ("MioFrame");
setSize (300,200);
addWindowListener (new WindowAdapter()
{ public void windowClosing (WindowEvent e) {System.exit(0);}
} ); // Istruzione per chiusura frame
Container contentPane=getContentPane();
contentPane.add (new MioPanel()); // Crea+Insert MioPanel in MioFrame
}
}
class MioPanel extends JPanel // Definisce classe MioPanel
{ public void paintComponent (Graphics gr)
{ super.paintComponent (gr); // Prepara sfondo, ecc.
gr.drawString ("Stringa (disegnata)",75,100); // Disegna stringa
}
}
public class TestMioFrame
public static void main (String[]args)
{ JFrame frame=new MioFrame(); // Crea MioFrame con inserito MioPanel
frame.show(); // Display MioFrame
}
}
L'aggiornamento del display e' fatto automaticamente dalle finestre, sotto
controllo del gestore di eventi Java, per cui se la schermata dev'essere
ridisegnata e' opportuno usare il metodo repaint anziche' paintComponent,
per non interferire con il processo di aggiornamento automatico.
Per l'approfondimento relativo alla gestione dei font e dei colori si
rimanda al testo.
⌡ 14.5.4 - Metodi per disegnare immagini
----------------------------Per inserire un'immagine memorizzata sul disco locale o su Internet si
deve prima leggerla in formato GIF o JPEG, in un oggetto Toolkit usando
il metodo getDefaultToolkit della classe Toolkit.
Esempio di lettura di un'immagine dall'hard-disk locale:
String name="gifIcon.gif";
Image image=Toolkit.getDefaultToolkit().getImage(name);
Esempio di lettura di un'immagine da Internet:
URL u=new URL("http://www.sito.com/gifIcon.gif");
Image image=Toolkit.getDefaultToolkit().getImage(u);
La variabile oggetto image punta all'oggetto, che incapsula l'immagine del
file gifIcon.gif e che puo' essere visualizzato con il metodo drawImage
della classe Graphics:
public void paintComponent (Graphics g)
{ ......
gr.drawImage (image,x,y,null);
}
Nel display di immagini si presentano problemi particolari (per esempio
dovuti al ritardo dello scaricamento delle immagini dal Web), su cui non
vogliamo soffermarci e per i quali rimandiamo al testo per i dettagli.
Sul dischetto delle esercitazioni e' riportato l'esempio (IconTest.java)
seguente:
/**
* Crea un frame richiudibile con immagine (icona) e lo mostra su video
*/
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
// ---- Definisce IconFrame con titolo, ampiezza e posizione ---class IconFrame extends JFrame
{ public IconFrame ()
{ setTitle ("IconFrame");
setSize (300,200);
setLocation (100,50); // Posiziona il frame (0,0=alto a sinistra)
Toolkit tk=Toolkit.getDefaultToolkit(); // Crea l'oggetto Toolkit
Image img=tk.getImage ("gifIcon.gif"); // Vi incapsula l'immagine
setIconImage (img); // Definisce l'immagine img come icona del frame
addWindowListener (new WindowAdapter()
{ public void windowClosing (WindowEvent e) {System.exit(0);}
}); // Termina il thread (chiude il frame) a fine main
}
}
// ---- Crea l'oggetto frame con icona e lo mostra (in alto a sinistra) ---class IconTest
{ public static void main (String[]args)
{ JFrame frame=new IconFrame();
frame.show();
}
}
⌡ 14.6 - EVENTI (I/O handling)
=====================
Gli eventi generalmente sono acquisiti sotto interruzione dal sistema
operativo (con le dovute priorita'). Il sistema operativo li presenta
quindi alla parte di AWT (Abstract Window Toolkit), con cui comunica,
che li trasforma in eventi AWT e li deposita in un'apposita coda di
eventi gestita dal Java run-time.
Un'altra parte di AWT trasmette poi gli eventi ai 'listener', eseguendo
nell'ordine le seguenti operazioni:
1) Preleva un evento dalla coda;
2) Individua l'oggetto listener di tale evento;
3) Esegue il metodo del listener relativo a quell'evento.
Il sistema run-time di Java 2 VM quindi acquisisce gli eventi off-line,
gestendoli con i metodi predisposti dal programmatore, secondo le modalita'
che specificheremo in questo paragrafo.
Le interruzioni sono gestite dal nucleo del sistema operativo del computer
locale e le relative informazioni (che chiameremo eventi o pseudo-interrupt)
sono passate a Java 2 come messaggi.
Per far funzionare questo sistema occorre prima attivare nel programma Java
le possibili sorgenti degli eventi con il metodo seguente (in cui 'this'
indica che la gestione dell'evento con 'actionPerformed' e' nello stesso
programma):
addActionListener (this); // Attiva pseudo-interrupt
e poi quando gli eventi sono ricevuti da Java, vanno gestiti con il metodo
appropriato, predisposto dal programmatore (pseudo-interrupt handler), che
viene indicato con l'istruzione seguente:
actionPerformed (ActionEvent evt)
Anche in questo caso descriviamo le modalita' di programmazione realizzando
un primo esempio di programma funzionante.
Per questo prima introduciamo gli elementi di programmazione necessari e
poi costruiamo gradualmente il programma di gestione di una finestra con
tre pulsanti funzionanti.
⌡ 14.6.1-DICHIARAZIONI NECESSARIE ALLA CLASSE PER RICEVERE E GESTIRE EVENTI
-----------------------------------------------------------------Occorre per prima cosa rendere accessibile la library java.awt.event con
l'istruzione seguente:
import java.awt.event.*;
Poi occorre 'linkare' l'interfaccia appropriata (es. ActionListener per il
pulsante del mouse o l'Invio della tastiera) con lo statement 'implements'
nella dichiarazione della classe. Esempio:
public class Graph extends java.applet.Applet implements ActionListener {
Le interfacce disponibili, cioe' l'equivalente delle routines di servizio
delle interruzioni, comprendenti la chiamata ad un corrispondente metodo
predisposto dall'utente (per esempio ad 'ActionListener' corrisponde
'actionPerformed()'), per personalizzare l'azione di risposta all'azione,
sono le seguenti:
1)
2)
3)
4)
ActionListener per il pulsante del mouse o l'Invio della tastiera;
MouseListener per il mouse;
ItemListener per la scelta tra una lista o tra check-boxes;
..... ecc.
Si possono rendere disponibili piu' interfacce, scrivendone i nomi dopo
la parola chiave 'implements' separati da virgola, come nell'esempio
seguente:
public class Graph extends java.applet.Applet implements ActionListener,
ItemListener {
⌡ 14.6.2 - ATTIVAZIONE ED ATTESA DI UN EVENTO
---------------------------------L'attivazione dell'attesa di un evento equivale all'abilitazione di un
interrupt: per attivare la ricezione del pulsante del mouse (o del tasto
'Invio' della tastiera), cioe' per permettergli di generare un evento,
dopo aver caricato ActionListener occorre per prima cosa creare su video
il pulsante con l'oggetto 'Button', contenuto in ActionListener (JButton
nella libreria Swing di interfacce utente GUI).
Questo si fa richiamando il metodo add, come nell'esempio riportato in
⌡14.5.1, dove il pulsante viene anche inserito in un frame (crea ed attiva
il pulsante 'redButton' con dentro la scritta "Red"):
redButton = new JButton ("Red");
add (redButton);
In Java 2 con i componenti GUI di Swing l'inserimento in un frame (finestra
top level) di un pulsante si fa come nell'esempio delle esercitazioni, che
qui riportiamo (PulsTest.java):
// ===== Esempio che crea un frame con 1 pulsante e lo mostra su video =====
import java.awt.*; // Rende disponibile la library Abstract Window Toolkit
import java.awt.event.*; //
"
"
java.awt.event
import javax.swing.*;
//
"
i componenti d'interfaccia Swing
// ---- Definisce il pulsante con titolo ---class PulsInPanel extends JPanel
{ public PulsInPanel()
{ redButton=new JButton ("Red");
add (redButton);
}
private JButton redButton;
}
// --- Definisce PulsFrame (=contenitore) con titolo,ampiezza e posizione --class PulsFrame extends JFrame
{ public PulsFrame ()
{ setTitle ("Pulsante in Frame");
setSize (300,200);
setLocation (100,50); // Posiziona il frame (0,0=alto a sinistra)
Container contentPane = getContentPane ();
contentPane.add (new PulsInPanel());
}
}
// ---- Crea l'oggetto frame con il pulsante e lo mostra ---class PulsTest
{ public static void main (String[]args)
{ JFrame frame = new PulsFrame ();
frame.show ();
}
}
⌡ 14.6.3 - GESTIONE DEGLI EVENTI
--------------------Si fa con il metodo 'actionPerformed', che svolge le funzioni di un
'user interrupt handler'.
Ogni sorgente di eventi (attivati), relativa ad una periferica, ha un
corrispondente metodo che dev'essere predisposto dall'utente per
intraprendere le azioni conseguenti al verificarsi dell'evento.
Per esempio, in aggiunta all'attivazione del redButton di cui sopra,
bisogna inserire (nello stesso programma, perche' nell'esempio c'e'
'this') il metodo seguente:
void public actionPerformed (ActionEvent evt)
{
..... // Mettere qui' le istruzioni per l'user 'interrupt' handling
}
L'oggetto ActionEvent evt identifica la sorgente dell'interruzione con il
metodo evt.getSource():
Object source = evt.getSource();
Utilizzando source il programmatore puo' far intraprendere al programma
le azioni dovute con il metodo actionPerformed, come mostrato nell'esempio
seguente TestEvent.java):
// ---- Esempio che gestisce l'evento 'Pressione di un pulsante' ---import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
// --- Definisce i 3 pulsanti con titolo e ne attiva gli eventi --class PulsInPanel extends JPanel implements ActionListener // ***
{ public PulsInPanel()
{ yellowButton=new JButton ("Yellow");
redButton=new JButton ("Red");
blueButton=new JButton ("Blue");
add (yellowButton);
add (redButton);
add (blueButton);
yellowButton.addActionListener (this); // Attiva pseudo-interrupt
redButton.addActionListener (this);
blueButton.addActionListener (this);
}
// ---- Metodo di gestione degli eventi (pseudo-interrupt handler) ---//
(Azione: al click su un pulsante ridisegna il frame con il nuovo colore)
public void actionPerformed (ActionEvent evt)
{ Object source = evt.getSource();
Color color = getBackground();
if (source==yellowButton) color=Color.yellow;
else if (source==redButton) color=Color.red;
else if (source==blueButton) color=Color.blue;
setBackground (color);
repaint();
}
private JButton yellowButton;
private JButton redButton;
private JButton blueButton;
}
// Termine del metodo costruttore
// --- Definisce PulsFrame (=contenitore) con titolo, ampiezza e posiz.--class PulsFrame extends JFrame
{ public PulsFrame ()
{ setTitle ("Pulsanti in Frame");
setSize (300,200);
setLocation (100,50); // Posiziona il frame (0,0=alto a sinistra)
//
L'istruzione seguente termina il thread alla chiusura del frame
addWindowListener (new WindowAdapter()
{ public void windowClosing(WindowEvent e) {System.exit(0);} });
Container contentPane = getContentPane();
contentPane.add (new PulsInPanel());
}
}
// ---- Crea l'oggetto frame con 3 pulsanti e lo mostra sul video ---class TestEvent
{ public static void main(String[]args)
{ JFrame frame = new PulsFrame();
frame.show();
}
}
Molte altre informazioni sono necessarie al programmatore di interfacce
GUI, poiche' molteplici sono gli eventi possibili.
Si dovra' anche imparare, per esempio, a gestire gli eventi della tastiera
o ad accedere alla coda degli eventi AWT.
Per questo rimandiamo chi volesse approfondire questa conoscenza al libro
di testo di Java 2, cap.8. Nella pratica comunque il compito e' facilitato
dagli appositi sistemi integrati per sviluppo di applicazioni Java (come
Symantec Visual Cafe' o Borland Jbuilder o IBM VisualAge o Sybase PowerJ).
Con essi si puo' produrre facilmente i codici di interfaccia grafica
necessari alle proprie applicazioni, evitando cosi' di entrare in dettagli
di programmazione lunghi e tediosi (che e' comunque sempre opportuno
conoscere).
!--------------------------------------------------⌡ 14.7 - APPLET JAVA
===========
⌡ 14.7.1 - Premessa
-------Il primo browser capace di eseguire i bytecode delle applet con una
macchina virtuale Java e' stato HotJava, presentato nel 1995 dalla
Sun: esso era stato scritto completamente in Java per dimostrare le
potenzialita' del linguaggio.
Questa capacita' di eseguire applet inserite nelle pagine Web non ha
comportato pero' una grande diffusione di HotJava, perche' pochi utenti
erano disposti a cambiare browser solo per acquisire questa nuova
funzionalita'.
La popolarita' delle applet si e' estesa quando, nel 1996, anche Netscape
ha incluso una macchina virtuale Java nella nuova release suo browser
Netscape 2.0, spingendo cosi' anche Internet Explorer a fare la stessa
cosa.
Il linguaggio Java da allora si e' sviluppato molto rapidamente dalla
versione 1.0, gestita da questi browser nel 1996. Meno rapidamente sono
stati aggiornati i browser, per cui oggi solo le loro versioni piu' recenti
sono in grado di gestire buona parte di Java 1.1, ma non ancora Java 2.
In aggiunta a questa problematica nell'uso del linguaggio Java nelle applet,
c'e' da considerare che vi sono fastidiose limitazioni ed incompatibilita'
tra linguaggio e browser. Cio' perche' Microsoft probabilmente non fara'
gestire al suo browser quelle parti di Java che risultano concorrenziali
con la propria tecnologia. Inoltre Netscape che potrebbe farlo e' ormai
praticamente uscita dal mercato delle macchine virtuali (consentira' pero'
l'uso di altre macchine virtuali Java nel proprio Navigator).
Per combattere questa situazione, che potrebbe compromettere l'uso delle
applet Java, Sun ha rilasciato un pacchetto, chiamato Java Plug-In, che
innestandosi nei due browser Navigator ed Explorer, consente loro di
eseguire applet Java con tutte le funzionalita' aggiornate, utilizzando
un ambiente run-time esterno fornito da Sun.
La macchina virtuale risultante potra' cosi' essere mantenuta aggiornata
da Sun, per permettere di eseguire anche le nuove funzionalita' del
linguaggio, comprese nelle versioni Java 2 e successive.
Questa soluzione risulta pero' un po' limitativa per le applicazioni
in rete globale perche', se il visitatore di una pagina Web non ha sul
proprio computer il Java Plug-In gia' installato, gli si deve richiedere
di installarlo per vedere l'applet, cliccando sull'apposito pulsante che
l'amministratore del sito potra' aver predisposto per consentire il
download del Plug-In.
Questa procedura, oggi largamente usata, produce una diffusione del
Plug-In, anche se e' un pacchetto voluminoso, poiche' basta caricarlo
una sola volta.
L'alternativa all'uso del Plug-In sarebbe quella di programmare applet con
le sole funzioni di Java 1.0; in tal caso pero' l'applet risulterebbe piu'
semplice ed allora presumibilmente sarebbe anche possibile farne a meno,
realizzando le sue funzionalita' con altri strumenti come JavaScript per
le funzioni logiche dei programmi, i form per l'immissione dei dati ed i
file GIF per le animazioni.
Questa situazione sembra limitare un poco l'utilizzo in rete delle applet
Java per le applicazioni piu' complesse, anche per il maggior onere
temporale dello scaricamento da rete di codici estesi, lasciando invece
intatte tutte le potenzialita' del linguaggio Java per le applicazioni
da eseguire sulle macchine locali, al fine di usufruire dei suoi vantaggi
quali l'indipendenza dalla piattaforma e l'accesso agevolato ai database
ed alla rete.
L'istallazione sul Web pero' offre altri vantaggi quali la disponibilita'
per l'utente di piu' applicazioni che non sul disco locale, la maggiore
facilita' di manutenzione ed aggiornamento delle applicazioni (basta
aggiornare l'unica copia sul Web anziche' le copie locali sui computer di
tutti gli utenti).
Per questo oggi un fertile campo per le applicazioni Java di successo e'
quello delle reti Intranet aziendali. In questi casi l'istallazione 'una
tantum' dei Plug-In sulle macchine della rete Intranet non pone problemi
e la maggiore larghezza di banda consente di trasferire efficientemente
anche codici estesi.
Il quadro risultante per l'uso delle applet e' cosi' il seguente:
1) Nelle reti Intranet, con i Plug-In istallati su tutti i computer client,
si utilizzano applet, con le funzioni Java piu' avanzate, per avere meno
problemi di portabilita', una migliore manutenibilita' del software ed
una maggiore flessibilita' nella programmazione.
2) Sulla rete globale Internet, volendo evitare al visitatore l'istallazione
del Plug-In, si possono usare (invece delle applet):
- lo scripting per le convalide;
- i file GIF per le animazioni;
- i form e l'elaborazione su server (script CGI, servlet Java o
linguaggi di scripting per server) per l'immissione dei dati.
Nei limiti del nostro corso, ci limiteremo ora a mostrare con alcuni esempi
come si programma e come funziona un'applet Java, lasciando poi alla buona
volonta' dello studente gli eventuali approfondimenti, reperibili sul testo
(Horstmann).
⌡ 14.7.2 - Esempi di applet
---------------Le applet sono programmi Java di particolare interesse poiche' sono
programmi che vengono scaricati attraverso la rete con le pagine HTML ed
il loro codice (bytecode) viene eseguito dall'interprete Java, chiamato
Virtual Machine (VM), contenuto nei browser, come Netscape Navigator o
MS Internet Explorer o HotJava della Sun (scritto in Java).
Per provarli, se si vuole evitare di caricarli con un browser WEB, viene
fornito con i sistemi di sviluppo dei programmi un apposito visualizzatore
di pagine HTML chiamato 'appletviewer': con esso faremo le nostre prove.
La diversita' dell'ambiente in cui le applet lavorano (la pagina HTML)
comporta che esse hanno una struttura diversa da quella delle applicazioni
Java viste finora.
Per prima cosa le applet non hanno un blocco main().
Hanno invece vari altri blocchi in funzione di quello che devono fare.
Due blocchi standard sono:
1) init() per inizializzare quanto occorre;
2) paint() per impostare la grafica necessaria.
Vediamoli all'opera su un esempio gia' visto in precedenza, trasformato ora
in applet (tutti i files sono presenti sul dischetto delle esercitazioni):
/* ---- Primo esempio di Applet ---Dopo la compilazione con:
javac PrimoApplet.java
puo' essere eseguito con:
appletviewer PrimoApplet.html
*/
public class PrimoApplet extends java.applet.Applet
{
int numero;
// --- Blocco di inizializzazione --public void init ()
{ numero = 225;
}
// --- Display di testo+dato dentro l'applet (posiz.=25,50) --public void paint (java.awt.Graphics gr)
{ gr.drawString ("La radice quadrata di " + numero
+ " e' " + Math.sqrt(numero),25,50);
}
}
Questa applet dev'essere inserita in una pagina HTML che possiamo battere,
nella sua forma piu' semplice, con un comune editor e poi salvare con il
nome PrimoApplet.html:
<applet code="PrimoApplet.class" height=100 width=300>
</applet>
In questo file abbiamo inserito il nome dell'applet e le dimensioni della
finestra di display dell'applet.
L'esecuzione, con l'ausilio dell'appletviewer, si ottiene battendo:
appletviewer PrimoApplet.html
⌡ 14.7.3 - Passaggio di parametri ad un'applet
----------------------------------Si possono passare parametri ad un'applet da una pagina HTML con il tag
<param> modificando cosi' il file PrimoApplet.html:
<applet code="SecondoApplet.class" height=100 width=300>
<param name="NUMERO" value=196>
</applet>
Le modifiche richieste nel programma SecondoApplet.java, per acquisire il
numero, sono quelle indicate nel blocco init():
/* --- Secondo esempio di Applet con lettura di parametro su pagina HTML --Dopo la compilazione con:
javac SecondoApplet.java
puo' essere eseguito con:
appletviewer SecondoApplet.html
*/
public class SecondoApplet extends java.applet.Applet
{
int numero;
// --- Blocco di inizializzazione --public void init ()
{ String parameter = getParameter("NUMERO"); // <----- Righe cambiate
if (parameter!=null) numero=Integer.parseInt(parameter); // "
"
}
// --- Display di testo+dato dentro l'applet (posiz.=25,50) --public void paint (java.awt.Graphics gr)
{ gr.drawString ("La radice quadrata di " + numero
+ " e' " + Math.sqrt(numero),25,50);
}
}
Per vedere il risultato bisogna poi, anche in questo caso:
1) Compilare con
javac SecondoApplet.java
2) Eseguire con
appletviewer SecondoApplet.html
Si possono passare quanti parametri occorrono con il tag <param>, purche'
ognuno abbia un attributo 'name' diverso. Questo apre la possibilita' al
server Web di confezionare appositamente delle pagine HTML con parametri
da passare all'applet in funzione dei risultati delle elaborazioni da lui
eseguite.
Un'utile sorgente di informazioni su come funzionano le applet ed i tag
HTML sono le pagine WEB scaricate dalla rete. Basta visionarne il codice
HTML:
- con Navigator cliccare su: View --> Document --> Source
- con Explorer cliccare su: View --> Source
⌡ 14.8 - PROBLEMI DI SICUREZZA E PROGRAMMAZIONE IN RETE
==============================================
⌡ 14.8.1 - Sicurezza con le applet
----------------------Una volta scaricata una pagina Web il browser (se abilitato) esegue tutte
le applet che vi incontra.
L'utente non ha possibilita' di confermare o interrompere l'esecuzione.
Quindi e' necessario considerare i problemi di sicurezza, dato che navigando
in rete possiamo scaricare da un sito remoto pagine contenenti applet di
provenienza non garantita, che potrebbero anche minacciare l'integrita' del
nostro sistema locale.
Per questo motivo nel browser sono state inserite delle apposite funzioni
per la gestione della sicurezza delle applet: quando un'applet tenta di
violare le regole di accesso stabilite, viene prodotta un'eccezione di tipo
SecurityException che ne blocca l'attivita'.
Vediamo allora, nel rispetto di queste regole, cosa possono fare e non fare
le applet.
- Le
1)
2)
3)
4)
applet possono:
visualizzare immagini;
riprodurre suoni;
ricevere pressione di tasti e click del mouse;
trasmettere all'host l'input dell'utente (per esempio per fare un
ordine di commercio elettronico).
- Le applet non possono:
1) alterare il sistema dell'utente;
2) prelevare informazioni contenute nel sistema dell'utente (come il
nome dell'utente, il suo indirizzo di posta elettronica, ecc);
3) avviare un programma sul sistema dell'utente;
4) comunicare con un host diverso da quello da cui sono state prelevate
(server di origine).
5) leggere o scrivere sul file system del computer client;
Questi controlli sono possibili perche' il bytecode Java e' eseguito sotto
interprete, che puo' verificare l'istruzione prima di eseguirla, impedendo
cosi' l'esecuzione di applet 'ostili', che possono violare le regole della
sicurezza (vedi libro a pag.528).
Queste restrizioni risultano pero' anche fortemente limitative delle
possibilita' di programmazione in rete offerte dal linguaggio Java.
Per risolvere questi problemi e' stata introdotta la tecnica delle firme
digitali, che trattiamo per completezza e perche' la sua conoscenza puo'
risultare utile anche nel mondo del lavoro.
⌡ 14.8.2 - Certificati e firme digitali
---------------------------Si tratta di una tecnica che garantisce sia l'autenticita' di un messaggio
ricevuto su Internet (cioe' che non e' stato intercettato e modificato
da un eventuale hacker), che l'identita' del mittente.
Per garantire l'autenticita' di un messaggio gli si aggiunge una stringa,
chiamata 'message digest', risultante dall'applicazione di un algoritmo
al messaggio (come per i check-sum). Per esempio JDK1.2 usa due algoritmi:
SHA-1 che produce una stringa di 20 bytes e MD5 che ne produce una di 16.
Questo pero' non e' sufficiente poiche', essendo gli algoritmi di dominio
pubblico, un hacker potrebbe intercettare il messaggio, modificarlo, calcolare la nuova stringa e reinstradarlo al destinatario, che non potrebbe
accorgersi della manipolazione.
Per risolvere il problema si puo' criptare il 'message digest' con una
chiave segreta. Se questa fosse unica pero' andrebbe usata sia per
criptare che per decriptare e quindi l'utente di una banca non avrebbe la
garanzia che questa chiave, nota anche agli impiegati della banca, non
possa essere divulgata, vanificando cosi' la sicurezza ricercata.
Si e' cosi' introdotto un sistema di crittografia del 'message digest'
basato su una coppia di chiavi: una 'chiave privata' a disposizione del
mittente, con cui cripta il message digest, e l'altra 'pubblica' con
cui il destinatario puo' decriptare il message digest, con tutta sicurezza
poiche', se un eventuale hacker tentasse la ricodifica del message digest
con una sua coppia di chiavi, il destinatario ricostruirebbe con la sua
chiave pubblica un message digest diverso da quello inviato dall'hacker.
La firma digitale (digital ID) consiste in questo metodo di criptaggio
dei message digest (e non del messaggio che puo' anche essere spedito
in chiaro).
Si ottiene cosi' la garanzia che il messaggio non e' stato indebitamente
manipolato lungo la rete.
La segretezza del messaggio e' un altro problema che viene affrontato con
altri diversi metodi specifici di crittografia.
Per garantire l'autenticazione del messaggio occorre pero' risolvere
anche un altro problema: come si puo' garantire che la chiave pubblica
sia autentica e che non sia stata inviata da qualcuno che vuole spacciarsi
per qualcun'altro?
Per questo e' stato introdotto il 'certificato di autenticita'. Esso
permette di risalire dalla chiave pubblica, consegnata al destinatario
insieme al certificato, alle generalita' del mittente contenute nel
certificato stesso. Quest'associazione, tra chiave pubblica e generalita'
del mittente, e' garantita dalla firma digitale di un'autorita' di
certificazione (CA), la cui autenticita' puo' essere verificata con la
chiave pubblica della stessa CA, presente su un suo certificato che
accompagna sempre quello del mittente.
Questo autocertificato della CA viene trasmesso proprio perche' funge da
contenitore della chiave pubblica della CA.
I certificati vengono rilasciati a pagamento dalle CA (per esempio la
Verisign fa pagare $20/anno). Per imparare a programmare invece si possono
usare gli autocertificati ottenibili con gli strumenti di Java, Netscape
e Authenticode di MS (che non hanno valore legale).
⌡ 14.8.3 - Thrusted applets
---------------Le applet sono limitate nelle loro possibilita' dal Security Manager di
Java (si dice che le limita nella sandbox), come spiegato in precedenza.
E' pero' possibile concedere loro di eseguire anche le operazioni
potenzialmente pericolose per la macchina client, rendendole 'thrusted
applet', ovvero passando l'iter dell'autenticazione con la tecnica del
certificato di autenticita' e della firma digitale.
In altre parole l'utente, avendo la garanzia dell'identita' del mittente
di un'applet, concede di ridurre le protezioni nel proprio browser al
fine di consentire all'applet di scrivere sull'hard disk locale, di
avviare l'esecuzione di programmi, ecc. per svolgere un piu' sofisticato
lavoro di programmazione in rete.
La procedura per creare un 'thrusted applet' e mandarlo in esecuzione
sulla macchina client non e' affatto semplice e richiede l'uso di vari
strumenti.
Noi li esamineremo in dettaglio, non solo per imparare a gestire
applicazioni di commercio elettronico o di banking in rete (per qualche
studente sicuramente risultera' utile), ma anche perche' questo e' il
metodo per controllare la concessione di privilegi di accesso alle
risorse locali alle applet Java sulle macchine client, e questo e' un
passo fondamentale che ci permettera' di progettare la programmazione
distribuita in rete di applicazioni scientifiche.
Il produttore dell'applet deve:
- produrre un certificato e creare una coppia di chiavi (digital ID);
- porre la coppia di chiavi in un database detto 'keystore'
- inserire l'applet in un archivio .jar e firmarlo
- esportare il certificato con la chiave pubblica (cioe' con KeyTool.exe
genera un file .cer che va inviato al destinatario)
L'utente destinatario deve:
- inserire nel proprio keystore il certificato
- concedere i privilegi di accesso richiesti sulla propria macchina
usando il PolicyTool
Il modo piu' veloce per imparare ad usare i thrusted applets e' di
farne funzionare uno. Per questo mostreremo un esempio riportato nei
tutorial di Java al sito:
http://java.sun.com/docs/books/tutorial/security/1.2/toolsign/index.html
⌡ 14.8.4 - Sicurezza sotto Security Manager di Java (JDK1.2)
------------------------------------------------Seguendo l'esempio della Sun eseguiremo tutti i passi necessari per la
creazione, distribuzione ed esecuzione di un thrusted applet, usando
gli strumenti del JDK1.2 (keytool, jarsigner, PolicyTool e jar).
Programmi e dati del test li caricheremo in un'apposita directory
C:\Test.
A) Nell'esempio il produttore dell'applet e' Tizio.
Per prima cosa si dovra' generare una coppia di chiavi che mettera'
in un database keystore, che chiamera' tiziostore.
Nel sistema il certificato e le chiavi saranno referenziati con uno
pseudonimo (detto alias in Java e nickname in Netscape). Per Tizio
sara' usato l'alias 'signFiles' per le chiavi che sono in tiziostore.
Poi Tizio dovra' produrre il proprio certificato di autenticita' che
sara' chiamato Tizio.cer
Infine dovra' inserire il thrusted applet in un contenitore .jar e
apporgli la firma.
B) L'utente destinatario nell'esempio si chiama Caio.
Egli dovra' importare il certificato di Tizio in un proprio keystore,
che chiamera' caiostore, e lo referenziera' con l'alias 'tizio'.
Dovra' poi usare il proprio PolicyTool per stabilire quali privilegi
concedere al thrusted applet di Tizio (puo' accorgersi di quali sono
necessari all'applet facendolo eseguire e segnando tutti i messaggi
di SecurityException forniti dal Security Manager di Java ogni volta
che si tenta l'accesso ad una risorsa protetta).
Potra' poi eseguire l'applet sotto tutela del Security Manager di
Java. Per questo occorre un'indicazione esplicita all'interprete:
... -Djava.security.manager ... (nelle applicazioni)
... -J-Djava.security.policy ...(negli applet)
Se eseguiamo il test su un solo computer (stand-alone), useremo la
stessa directory C:\Test per caricare sia i files di Tizio che quelli
di Caio.
Nel nostro esempio vogliamo eseguire un applet chiamato Writ.class, che
sara' contenuto nel file AppletWri.jar e che legge il file Test.dat
sull'hard disk locale per poi riscriverlo con lettere maiuscole: queste
elaborazioni sarebbero normalmente proibite dal Security Manager, ma se
eseguiamo le operazioni di firma digitale dell'applet che ora descriviamo,
l'applet, divenuto thrusted, potra' eseguirle senza ostacoli.
I codici della pagina HTML e dell'applet sono contenuti tra i files delle
esercitazioni con i nomi Writ.html e Writ.java:
<html>
<head><title>Prova thrusted applet</title></head>
<body>
<Applet Code="Writ.class" archive="AppletWri.jar" width=400 height=210>
</Applet>
</body></html>
// Esempio di Applet che legge Test.dat e scrive CapTest.dat (con maiuscole)
import java.io.*;
import java.awt.*;
public class Writ extends java.applet.Applet
{
public void paint (Graphics g)
{
String NPath = getCodeBase().toString();
int LName = NPath.length();
NPath = "C:"+NPath.substring (8,LName);
File sorgente = new File(NPath,"Test.dat");
boolean esistefile = sorgente.exists();
Long LFile = new Long (sorgente.length());
if (esistefile==true)
{ g.drawString ("lunghezza del file "+NPath+"Test.dat: "
+LFile.toString()+"byte.",5,50);
try
{
File temp = new File (NPath,"CapTest.dat");
// --- Crea flusso input --FileReader fr = new FileReader (sorgente);
BufferedReader in = new BufferedReader (fr);
// --- Crea flusso output --FileWriter fw = new FileWriter (temp);
BufferedWriter out = new BufferedWriter (fw);
boolean eof = false;
int inChar = 0;
// --- Loop lettura+modifica+scrittura --do
{ inChar=in.read();
if (inChar!=-1)
{
char outchar=Character.toUpperCase ((char)inChar);
out.write (outchar);
}
else eof=true;
} while (!eof);
in.close();
out.close();
}
catch(IOException e) {g.drawString("Errore-"+e.toString(),5,50);}
catch(SecurityException se) {g.drawString("Errore-"
+se.toString(),5,50);}
} else g.drawString("Il file "+NPath+"Test.dat non esiste.",5,50);
}
}
Le operazioni necessarie per firmare questo applet sotto Security Manager
di Java JDK1.2 sono, nell'ordine:
OPERAZIONI DEL PRODUTTORE DEL SOFTWARE (Tizio)
==============================================
Generazione della coppia di chiavi
---------------------------------Cominciamo con la generazione di una coppia di chiavi con lo strumento
keytool:
c:\Test\keytool -genkey -alias signFiles -keypass kpi135 -keystore tiziostore
-storepass ab987c
Sono richieste due chiavi (che occorre appuntarsi perche' saranno richieste
anche nel seguito). Esse sono:
keystore password = ab987c (protegge l'intero keystore)
keyentry password = kpi135 (protegge la chiave privata)
Rispondere quindi alle domande poste dal keytool sulle proprie generalita'.
Questo comando genera il keystore 'tiziostore' in C:\Test ed un
autocertificato valido per 90 giorni.
Le chiavi, contenute in tiziostore, saranno referenziate con l'alias
signFiles.
Generazione dell'autocertificato
-------------------------------Si fa con la funzione export di keytool:
c:\Test\keytool -export -keystore C:\Test\tiziostore -alias signFiles
-file Tizio.cer
Il tool chiede la password ab987c e genera il certificati Tizio.cer
nel database tiziostore relativo all'alias signFiles.
Inserimento dell'applet nel file contenitore .jar
------------------------------------------------Si fa con lo strumento jar.exe, avendo prima compilato Writ.java in C:\Test.
Se si e' gia' posizionati con cd \Test basta digitare:
jar cf AppletWri.jar Writ.class
Questo comando crea il file AppletWri.jar, che potremo firmare con:
c:\Test\jarsigner -keystore C:\Test\tiziostore -storepass ab987c
-keypass kpi135 AppletWri.jar signFiles
OPERAZIONI DELL'UTENTE DEL SOFTWARE (Caio)
==========================================
Verifica dei privilegi richiesti
-------------------------------Si esegue l'applet con il comando:
C:\Test\Appletviewer Writ.html
e si prende nota dei privilegi richiesti.
Importazione del certificato
---------------------------Per importare il certificato Tizio.cer fornito dal produttore nel
proprio keystore, chiamato 'caiostore', basta digitare:
c:\Test\keytool -import -alias tizio -file Tizio.cer -keystore caiostore
Quando chiede la chiave si puo' battere ab987c
Questo comando crea il keystore caiostore e vi inserisce il certificato
Tizio.cer, referenziandolo con l'alias 'tizio'.
Concessione dei privilegi (agli applet firmati tizio)
------------------------Si avvia il Policy Tool con C:\Test\Policytool
Si inserisce l'URL di keystore con:
Edit-->Change KeyStore e poi New KeyStore URL = file:/C:/Test/caiostore e
OK
Poi nella finestra Policy Tool cliccare su Add Policy Entry che permette di
associare all'alias tizio i privilegi richiesti.
Nella finestra Permission inserire:
FilePermission:
Target Name
:
Actions
:
java.io.FilePermission
<< ALL FILES >>
read,write,delete,execute
e
OK
Salvare quindi il policy file cosi' creato cliccando nella finestra del
Policy Tool su 'File' e 'Save As' e battendo come nome del file:
C:\Test\caiopolicy
Questo completa la procedura.
Se tutto e' andato bene in C:\Test devono esserci i seguenti files:
1)
2)
3)
4)
5)
AppletWri.jar
Writ.html
caiostore
caiopolicy
Test.dat (questo e' un qualunque file di testo da leggere con l'applet)
ESECUZIONE DEL TEST DEL THRUSTED APPLET
=======================================
Si fa con il comando:
C:\Test\Appletviewer -J-Djava.security.policy = caiopolicy Writ.html
L'esecuzione e' corretta se scrive:
"Lunghezza del file C:\Test\Test.dat: nnn byte"
e in C:\Test scrive il file CapTest.dat
⌡ 14.8.5 - Sicurezza sotto Security Manager di Netscape ed IE
-------------------------------------------------Purtroppo allo stato attuale di queste tecnologie le procedure da seguire
sono diverse per le varie Java VM e relative versioni.
⌡ 14.9 - PROMEMORIA FINALE
=================
⌡ 14.9.1 - RIEPILOGO SINTETICO
------------------Riportiamo gli elementi concettuali e le definizioni introdotte:
|--> ATTRIBUTI (dati, parametri in/out)
OGGETTO-->|
(CLASS=Master copy dell'oggetto)
|--> METODI (Comportamento, istruzioni)
METODI: sono i task distinti compresi nella classe (sezioni della class)
Esempio: println()
Metodi e variabili sono richiamabili con un '.' dopo l'oggetto
Esempio: Cocker.parla();
EVENTI: con essi si gestisce l'I/O acquisito sotto 'interruzione'.
--------- . ----------CLASSI (Programmi):
-----------------class = inizio di un programma o sottoprogramma
main = 'main program' (quello lanciato al RUN)
public class Cane
<---- class usabile per creare oggetti 'Cane'
{ String name;
<---- usa string variable 'name'=ATTRIBUTO
public void parla()
<---- metodo (comportamento) dell'oggetto
{ System.out.println ("Bau! Bau!");
}
<--- fine sottoprogramma parla (=Metodo di Cane)
}
<--- fine programma Cane (=Master copy degli oggetti 'Cane')
Uso:
CREAZIONE DELL'OGGETTO 'Cocker':
ASSEGNAZIONE DEGLI ATTRIBUTI A 'Cocker':
RICHIAMO DEL METODO 'parla' dell'oggetto 'Cocker':
RICHIAMO DELLA VARIABILE 'n' dell'oggetto 'virus':
Cane Cocker = new Cane();
Cocker.name="Chicca";
Cocker.parla();
virus.n = 92;
Esempio: l'istruzione Cocker.parla(); produce in output "Bau! Bau!")
OGGETTI:
-------Se nella classe Virus c'e' il metodo Virus (stesso nome), questo viene
eseguito alla prima definizione dell'oggetto.
Esempio:
// Programma principale
class VirusStart
{ public static void main (String arguments[])
{ Virus influenza = new Virus();
Virus raffreddore = new Virus();
Virus aids = new Virus();
System.out.println("Ci sono " + Virus.getVirusCount() + " virus.");
}
}
//
class Virus
{ static int virusCount = 0; <-- def.class variable=COMMON: non eseguibile
public Virus()
<--- metodo Virus (stesso nome: e' eseguito
{ virusCount++;
alla dichiarazione dell'oggetto)
}
static int getVirusCount()
{ return virusCount;
}
}
Eseguendo java VirusLook viene stampato: "Ci sono 3 virus."
Il simbolo ++ e' usato per l'incremento: es. influenza.virusCount++;
METODI (=sottoprogrammi):
------------------------Sono sottoprogrammi che hanno uno o piu' parametri in ingresso e uno
(=FUNCTION) o nessun parametro in uscita se c'e' void (=PROCEDURE con
passaggio di parametri di classe/oggetto, come area COMMON).
N.B. due metodi possono anche avere lo stesso nome se hanno un diverso
numero di parametri in ingresso.
Esempio di metodo inseribile nella classe virus per infettare filename
(ritorna con success=true se lo ha infettato):
boolean public infectFile (String filename)
{ boolean success = false;
// Qui' c'e' il codice infettante (se infetta mette success=true)
.................
return success;
<--- questa e' la variabile passata (del tipo
}
indicato nell'intestazione: FUNCTION)
Il metodo si richiama come le FUNCTION. Esempio se ho l'oggetto malaria
della classe virus, posso scrivere:
if (malaria.infectFile(currentFile))
System.out.println(currentFile + " e' stato infettato");
else
System.out.println(currentFile + " non e' stato infettato");
Un metodo getHour con 'public' si puo' usare per far accedere altri
programmi ad una variabile privata Hour:
int public getHour()
{ return Hour;
}
<--- Hour = valore ritornato
Altro esempio di metodo con attributo newValue in input (con 'public' e'
richiamabile anche fuori della classe):
void public setHour(int newValue)
<--- newValue = valore input
{
if (newValue<24) newHour = newValue;
}
<--- senza return, perche' non ritorna valori (void): e' una
PROCEDURE che modifica newHour=variabile di classe (=COMMON)
METODI DI CLASSE:
----------------Rendono disponibili le funzionalita' a tutta una classe anziche' ad un solo
oggetto. Hanno 'static' nella dichiarazione. Esempio:
static void showVirusCount()
{ System.out.println("Ci sono " + virusCount + " virus.");
}
Richiamabile con:
virus.showVirusCount();
!-----------------------------------------------------------CAPITOLO 15 - Programmazione sul Web: Web Server, HTML, CGI, Java applet
═══════════
Riassunto: In questo capitolo viene presentato il Web server ed una
breve introduzione al linguaggio HTML, alle pagine Web
dinamiche (con script CGI), ed attive (con tecnologia Java).
⌡ 15.1 - CENNI AL LINGUAGGIO HTML
-----------------------HTML (HyperText Markup Language) e', come dice il nome, un linguaggio
ipertestuale basato su marcatori (Markup), appositamente creato dai
ricercatori del CERN per creare pagine Web; lo scopo iniziale era quello
di scambiarsi rapidamente on-line documenti su supporto elettronico
anziche' cartaceo.
Nel 1990 con il progetto WWW (World Wide Web il metodo ipertestuale e
intuitivo per accedere alle risorse sulla rete), al CERN nasce Internet
com'? oggi con i browser HTML per la navigazione su Web, il primo dei
quali (Mosaic) nasce nel 1993.
Oggi le regole HTML sono stabilite dal consorzio W3 (vedi http://www.w3.org).
La tecnica di inserire con un text editor dei marcatori in un documento e'
stata usata fin dai tempi dei primi word processor. Inserendo nel testo
sequenze di caratteri che non potevano comparire nel documento originario
si davano direttive al programma di impaginazione e stampa per pilotarne
il comportamento: per esempio si usava una riga che inizia con un punto
esclamativo seguita dai caratteri dell'apposita direttiva per ottenere la
stampa con caratteri corsivi da quel punto in poi.
Con i marcatori (tag) HTML si definiscono gli elementi logici del documento,
come titoli, paragrafi, elenchi, ecc. Il programma di impaginazione e stampa
contenuto nel browser Web (Netscape, Explorer, ecc.) provvedera' ad assegnare
una formattazione standard che rendera' l'output gradevole.
Con la versione HTML 3.2 sono poi state introdotte anche delle ulteriori
funzioni di formattazione che permettono di sviluppare la creativita' degli
autori delle pagine Web. Per esempio per scrivere una frase in rosso basta
inserire il tag <font color="red"> nel modo seguente:
<font color="red">Nel mezzo del cammin di nostra vita</font>
Il tag </font> ne chiude l'effetto. Non tutti i tag necessitano del tag di
chiusura.
I tag sono 'case insensitive' cioe' possono essere scritti indifferentemente
con lettere minuscole o maiuscole.
Queste caratteristiche rendono HTML facile da usare perche' non presuppone
ne' conoscenze tecniche, ne' capacita' di programmazione. Grazie a cio'
molte persone hanno potuto avvicinarsi al Web Publishing senza particolari
ostacoli ed oggi su Internet esistono milioni di creatori di pagine Web.
HTML quindi non e' un vero linguaggio di programmazione ma un sistema di
marcatura di sorgenti composti da ipertesti, cioe' testi, senza alcun
elemento grafico, video o sonoro (anche se questi poi possono risultare
presenti nell'output prodotto dal browser) contenenti collegamenti
ipertestuali.
Un ipertesto e' un documento composto di argomenti contenenti riferimenti ad
altri argomenti (collegamenti ipertestuali) inseriti al fine di consentire
la lettura saltando da un argomento all'altro (navigazione). Un esempio di
utilizzo di ipertesti ? la Guida di Windows e Hypercard di Macintosh.
Un collegamento ipertestuale e' un puntatore contenuto in una pagina WEB che
punta ad un altro file sul WEB, che in genere e' un'altra pagina WEB, ma
potrebbe anche essere un file multimediale o addirittura un programma.
La presenza di un collegamento ipertestuale in un testo e' resa visibile dal
browser con un colore diverso, mentre risulta invisibile su un'immagine
(pero' il cursore cambia aspetto quando ci si passa sopra).
Cliccando su un collegamento ipertestuale il browser preleva il file
dall'indirizzo specificato e lo visualizza se e' una pagina HTML oppure lo
apre (con il programma associato: per esempio con un riproduttore di suoni
se e' un file WAV).
Il linguaggio ipertestuale HTML (HyperText Markup Language) e' quindi il
linguaggio che definisce le direttive per l'impaginazione e lo sviluppo di
documenti interattivi.
Il browser WEB esegue la formattazione della pagina in base a queste direttive (tag) contenute nel codice HTML, adeguando la larghezza delle righe
alla larghezza dello schermo o della finestra. Cosi' browser diversi
potranno mostrare visualizzazioni diverse per la stessa pagina WEB.
Tutti gli elementi della pagina (informazioni e link) sono cosi' al loro
posto ma l'aspetto sul video potr? essere diverso.
Le specifiche sono curate dal consorzio W3C (vedi http://www.w3c.org), cui
partecipano Adobe, HP, IBM, MS, Netscape, Novell, SoftQuad e Sun.
HTML permette la creazione di pagine WEB interattive, nelle quali possiamo
incorporare veri programmi con JAVA, GCI, ActiveX e VRML (Virtual Reality
Modeling Language, per la visualizzazione di scenari a tre dimensioni
all'interno delle pagine WEB).
La codifica delle direttive (tag) necessarie al browser per l'impaginazione,
nel codice HTML non sono un compito semplice, ma i nuovi editor HTML,
progettati secondo la tecnica WYSIWYS ("What You See Is What You Get")
sollevano l'utente dall'obbligo di conoscere i codici di formattazione del
linguaggio ipertestuale, lasciandolo concentrare pi? facilmente sul lavoro
creativo.
HTML permette di produrre documenti elettronici che hanno il pregio di poter
essere sfogliati con un computer, passando rapidamente da un argomento ad
un altro ('navigazione') tramite i collegamenti (link) presenti nelle pagine,
senza dover scorrere sequenzialmente il testo.
Le pagine Web cosi' prodotte possono essere messe a disposizione di tutti gli
utenti di Internet o limitata alla rete locale o Intranet aziendale.
Uno dei metodi migliori di comprendere come funzionano i marcatori HTML e'
quello di vederli all'opera su pagine Web fatte da altri. In questo modo,
oltre ad acquisire idee nuove, si puo' anche importare parti di codice HTML
nei propri files, dopo averli visualizzate, selezionate e copiate (con i
comandi messi a disposizione dal browser).
Gli strumenti software necessari per produrre documenti sorgente HTML sono:
1) Editor di testo (come NotePad), meglio se editor HTML (come Front Page o
Dreamweaver della Macromedia);
2) Browser (come Explorer o Netscape Navigator);
3) Programma FTP (File Transfer Protocol), per inviare i files sul server Web
(con Password e UserId, che impediranno ad altri di modificare i files);
4) Software grafico, se si vogliono inserire immagini nel testo (molte
immagini preconfezionate si possono reperire come 'clip art' su siti
come www.yahoo.com).
La pubblicazione della pagina Web prodotta puo' essere fatta sull'hard disk
della macchina locale per uso esclusivo dell'autore, o sulla rete locale
rendendola accessibile ai soli utenti abilitati della rete locale, o sulla
rete Intranet aziendale, compatibile Internet ed estesa geograficamente ma
non accessibile, agli utenti generici di Internet o su un Web server pubblico
di Internet, accessibile a tutti. Gli amministratori delle reti, contattabili
via E.mail, devono fornire le informazioni necessarie per la pubblicazione
sul Web.
L'uso del formato standard HTML favorisce lo scambio di documenti, rendendoli
indipendenti dalla piattaforma (CPU, sistema operativo, formato documenti di
output, ecc.).
⌡ 15.1.1 - GENERALITA' SUI MARCATORI (=TAG) HTML
------------------------------------I TAG si dividono in due categorie:
1) TAG che definiscono gli elementi del documento, come titoli, elenchi,
paragrafi, ecc.;
2) TAG che inseriscono oggetti come immagini, suoni, applet e sequenze
animate.
Un caso a parte sono i TAG che racchiudono i commenti: <!- ..commento.. ->
Molti TAG possono avere un attributo ed un secondo TAG di chiusura
composto dallo stesso TAG letterale, preceduto da una barra '/'.
Esempio:
<TAG>testo del documento</TAG>
o con attributo: <TAG BGCOLOR="#RRGGBB">testo del documento</TAG>
I TAG sono 'case insensitive' cioe' possono essere scritti indifferentemente
con lettere minuscole o maiuscole.
Siccome il browser eseguira' una formattazione automatica (pilotata dai TAG)
verra' ignorato ogni tentativo di formattazione compiuto dall'autore
inserendo righe vuote (con il tasto Invio) o spazi aggiuntivi.
Cioe' per esempio:
<TAG>testo del documento</TAG>
produce lo stesso effetto di:
<TAG>
testo del documento
</TAG>
Questo tipo di formattazione del sorgente puo' comunque essere fatta per
migliorarne la leggibilita'.
I TAG possono essere annidati: per esempio, si puo' ottenere la stampa in
grassetto e corsivo annidando i rispettivi TAG cosi':
<B><I>testo del documento</I><B>
(si noti l'ordine dei TAG di chiusura, che rispetta l'annidamento dei TAG).
MARCATORI DI STRUTTURA
---------------------I TAG di struttura che e' opportuno inserire SEMPRE sono i seguenti:
1) <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//IT">
Identifica il
formato del documento e la versione HTML usata. Non ha TAG di chiusura.
In sua assenza il browser non interpreta i TAG seguenti come direttive
di formattazione e li stampa cosi' come li incontra.
2) <HTML>...</HTML>
Identifica la codifica HTML
3) <HEAD>...</HEAD>
Identifica l'intestazione del documento
4) <TITLE>...</TITLE> Identifica il titolo del documento
5) <BODY>...</BODY>
Identifica il corpo del documento
All'interno del TAG <BODY> si possono facoltativamente inserire i seguenti
attributi per modificare i colori:
BGCOLOR="#RRGGBB" Modifica i colori Red,Green,Blue (RGB) definiti con 2
caratteri esadecimali (256 colori)
BACKGROUND="URL" Mette immagine come sfondo
TEXT="#RRGGBB"
Modifica i colori del testo nel corpo della pagina Web.
Esempio (pagina Web con sfondo):
<BODY BGCOLOR="#3399CC" TEXT="#FFFFFF">
Esempio di documento con i TAG di struttura (da usare come modello standard
di base per tutte le pagine HTML da creare):
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//IT">
<HTML>
<HEAD>
<TITLE>Titolo del documento</TITLE>
</HEAD>
<BODY>
Testo del documento
</BODY>
</HTML>
Esistono altri TAG di struttura che pero' non trattiamo in queste dispense
perche' si riferiscono a casi particolari.
MARCATORI PRINCIPALI
-------------------I TAG di struttura che seguono sono quelli presenti pressoche' in tutti i
documenti, per formattare i titoli, i paragrafi, gli elenchi e per fare
risaltare parti del testo. Basta inserire la coppia di TAG per ottenere
l'effetto voluto.
Marcatura di
<H1>...</H1>
<H2>...</H2>
.......
<H6>...</H6>
un titolo:
Titolo di primo livello (caratteri di dimensione massima)
Titolo di secondo livello (caratteri di dimensione minore)
seguono altri livelli da 3 a 5
Titolo di sesto livello (caratteri di dimensione minima)
Marcatura di un paragrafo:
<P>...</P> Indica un paragrafo ( </P> e' facoltativo )
<BLOCKQUOTE>...</BLOCKQUOTE> Indica un paragrafo da scrivere rientrato
Marcatori di evidenziazione:
<EM>...</EM> Evidenzia il testo racchiuso (generalmente in corsivo)
<STRONG>...</STRONG> Evidenzia al massimo il testo racchiuso
<B>...</B>
Evidenzia il testo in grassetto
<I>...</I>
Evidenzia il testo in corsivo
Marcatura di un elenco:
<OL>...</OL> Indica un elenco numerato sequenzialmente
<UL>...</UL> Indica un elenco non numerato (puntato)
<LI>
e' il TAG singolo (senza chiusura </LI>) che va messo
all'inizio di ogni voce dell'elenco (per numerare o puntare).
MARCATORI IPERTESTUALI PER COLLEGAMENTI (LINK)
---------------------------------------------Permettono di realizzare collegamenti ipertestuali sia interni ad uno stesso
documento, sia esterni verso file esterni sullo stesso server Web che su
altri computer collegati in rete.
Questi collegamenti si identificano con il TAG di ancoraggio:
<A>...</A> Definisce l'ancoraggio
al quale si associa un riferimento con gli attributi seguenti:
NAME="..." Definisce l'etichetta di destinazione del collegamento
(corrisponde al punto in cui e' inserito il TAG nel documento)
HREF="..." HyperText Reference: indica l'indirizzo collegato (interno o
esterno al documento) a cui saltare con un click.
Esempi:
<A HREF="#ancora">Testo</A> per Rif.in stessa pag, messo con <A
NAME='ancora'>
<A HREF="Pag2.htm">Testo</A> per Rif.in stesso sito (Pag2.htm in stesso sito)
<A HREF="http://www.globus.org">Testo</A> per Rif. esterni (sul Web)
<A HREF="mailto:[email protected]">Testo</A> per invio automatico E.mail
Per comprenderne il funzionamento invitiamo il lettore a sperimentare gli
esempi seguenti visualizzandoli con un browser.
Immettete prima il seguente testo con un editor (come NotePad) e salvatelo
poi con il nome c:\documenti\cani.html
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//IT"> |
<HTML>
|
<HEAD><TITLE>Cani</TITLE>
|
</HEAD>
|
<BODY>
| File cani.html
<H2>Abitudini dei cani</H2>
|
.... Testo del paragrafo .......
|
</BODY>
|
</HTML>
|
Avviate il vostro browser e caricate l'indirizzo c:\documenti\cani.html
per vedere il risultato.
Ora introducete nel file un'etichetta label1 nel modo seguente, salvandolo
con il nome c:\documenti\test1.html:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//IT">
<HTML>
<HEAD><TITLE>Cani</TITLE>
</HEAD>
<BODY>
<H2><A NAME="label1">Abitudini</A> dei cani</H2>
.... Testo del paragrafo .......
</BODY>
</HTML>
|
|
|
|
| File test1.html
|
|
|
|
Si osservi come questo ancoraggio non venga visualizzato dal browser.
Utilizziamo ora questo ancoraggio, inserendo un collegamento ad esso nel
testo dello stesso file salvandolo come test2.html, come segue:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//IT">
<HTML>
<HEAD><TITLE>Cani</TITLE>
</HEAD>
<BODY>
<H2><A NAME="label1">Abitudini</A> dei cani</H2>
.... Testo del paragrafo .......
I cani hanno le <A HREF="#label1">abitudini</A>.
</BODY>
</HTML>
|
|
|
|
|
| File test2.html
|
|
|
|
Questo collegamento, realizzato con il TAG <A HREF="#label1">, alla etichetta "label1", creata in altro punto dello stesso documento con il TAG
<A NAME="label1"> viene mostrato dal browser evidenziando la parola tra i
due TAG <A HREF="#label1">...</A>, cioe' "abitudini" e facendo cambiare il
puntatore quando passa sopra questa parola (aspetto tipico dei collegamenti).
Se il collegamento a #label1 viene invece fatto da una pagina esterna
a questo documento, che si trova come file test1.html sul server Web
cani.animali.org, si dovra' inserire nel testo l'indirizzo URL nel modo
seguente:
...... testo prec. ......
Studiamo le <A HREF="http://cani.animali.org/test1.html#label1">abitudini</A>
dei cani.
...... segue altro testo .....
Cliccando sulla parola evidenziata (cioe' abitudini, che e' compresa tra i
due TAG) il browser preleva dalla rete il file indirizzato (test1.html sul
server cani.animali.org con il protocollo http) e lo presenta su video alla
posizione dell'etichetta "#label1".
Lo scaricamento di files da un sito si fa allo stesso modo con l'URL del
sito ed il protocollo ftp anziche' http (si ricordi che gli URL fanno
differenza tra minuscole e maiuscole).
MARCATORI INSERIMENTO DI IMMAGINI
--------------------------------Il seguente TAG permette di inserire in un documento HTML files grafici in
formato GIF (disegni) o JPG (fotografie) e non in altri formati:
<IMG SRC="...">
Inserisce nel punto in cui e' il TAG l'immagine il cui
URL, assoluto o relativo, e' inserito al posto dei
puntini (non richiede TAG di chiusura).
Esempio: <IMG SRC="immagine.gif"> = Image Search
Sono previsti inoltre i seguenti attributi:
ALIGN="..." Allinea immagine nel documento
ALT="..."
Indica un testo alternativo da visualizzare se l'immagine non
viene visualizzata (per esempio perche' l'utente ha disabilitato
la visualizzazione di immagini per velocizzare il browser).
Esempio: <IMG SRC="image.gif" ALT="Commento">=Immagine+Commento
BORDER=n
Definisce il numero n di pixel della cornice di contorno della
immagine, cioe' il suo spessore.
HEIGHT=n
Definisce l'altezza della cornice di contorno dell'immagine
(n=numero di pixel)
WIDTH=n
Definisce la larghezza della cornice di contorno dell'immagine
(n=numero di pixel)
Esempio: <IMG SRC="image.gif" WIDTH=150 HEIGHT=180> =Immagine
Altri parametri (HSPACE, VSPACE, ALIGN) e marcatori per governare
allineamento e colori o per generare effetti speciali, immagini cliccabili,
ecc. sono disponibili, ma non sono inseriti in queste dispense e nel nostro
corso.
Tra marcatori ed attributi esistono oltre 300 definizioni da imparare.
Fortunatamente pero' questo lavoro e' reso largamente non necessario dai
vari editor HTML, che introducono automaticamente nel codice HTML la
codifica delle direttive (TAG) necessarie al browser per l'impaginazione,
In particolare i nuovi editor HTML, progettati secondo la tecnica WYSIWYS
("What You See Is What You Get") sollevano completamente l'utente dallo
onere di conoscere i codici di formattazione del linguaggio ipertestuale,
lasciandolo concentrare pi? facilmente sul lavoro creativo.
Libro (tascabile): Ray & Ray - HTML for dummies - Ed. Apogeo
Sito con guida interattiva: www.html.it
⌡ 15.2 - IL SERVER HTTP APACHE
--------------------A differenza del browser, il server Web e' un'applicazione abbastanza
semplice, che deve rimanere costantemente in ascolto delle richieste
che arrivano su una porta, per esaudirle.
Esso costituisce il lato server dell'applicazione tipica di Internet: la
navigazione in rete avviene infatti con un browser (client) che interroga
un Web server, ottenendone informazioni e servizi per l'utente.
Descriveremo qui' il Web server Apache, scaricabile gratuitamente dalla
rete, perche' lo useremo nelle esercitazioni pratiche e perche' e' meno
dipendente dalla piattaforma Microsoft-Windows.
Quando nel nostro browser impostiamo un URL (Uniform Resource Locator),
succede a grandi linee questo:
1) per prima cosa il nostro computer contatta il server HTTP, individuato
dall'URL da noi indicato;
2) il server HTTP cerca il nome del file che abbiamo richiesto nel nostro
URL e, una volta trovato, ci manda indietro il file;
3) come ultima cosa il nostro browser, una volta ricevuto il file, lo
esamina, lo elabora e ce lo mostra a video, nove volte su dieci come una
normale pagina Web (formato HTML).
E' anche possibile pero' configurare il server HTTP in modo che, ogni
volta che viene richiesto un file in una determinata cartella, non lo
mandi direttamente al client ma lo esegua (script CGI) come un vero e
proprio programma e solo l'output di tale programma venga inviato al
computer client nel giusto formato perche' lo visualizzi (pagina Web
dinamica).
Un esempio puo' essere il counter: il computer di chi entra nel sito
dove risiede il counter non fa alcuna elaborazione tranne visualizzare
il file grafico .gif (se si tratta di un counter grafico), risultato
dell'elaborazione fatta dal server: intercettare il visitatore,
preparare un'immagine con il numero di accessi ed inviarla al client
perche' la visualizzi.
Questa funzionalita' viene chiamata Common Gateway Interface e questi
programmi sono chiamati script CGI.
CGI significa "Common Gateway Interface" ed e' il metodo con cui un
server interagisce con database, documenti ed altri programmi, inviando
o ricevendo dati; questi dati saranno poi inviati sul web in formato
direttamente visualizzabile dal browser. Il linguaggio principale per
scrivere i CGI e' il Perl, anche se e' possibile utilizzare altri
linguaggi (soprattutto C).
Per fare queste cose occorre programmare un server Web: per esercitarsi
con queste tecniche di comunicazione non conviene lavorare su un vero
Web server in rete. E' meglio installare e configurare un server Web
su un PC disponibile, senza bisogno di reti e modem sempre collegati.
Avviandone il funzionamento in multitasking, il browser potra' cosi'
comunicare con un Web server Apache sullo stesso PC, simulando il
collegamento in rete (funzionamento loopback di TCP/IP, con indirizzo
127.0.0.1).
Per provare ad usare gli script CGI dovremo acquisire un minimo di
conoscenza del linguaggio Perl (anch'esso scaricabile gratuitamente
dalla rete) ed avere il suo interprete sul nostro PC.
Non tratteremo questi argomenti nelle lezioni, ma faremo esempi del
loro uso nelle esercitazioni.
Per capire meglio l'interazione tra browser e server Web e' opportuno
avere entrambi sul proprio PC e farli comunicare in multitasking,
simulando il collegamento in rete.
Per installare e configurare il Web server Apache sul proprio PC
stand-alone (per poter lavorare senza collegamento in rete), dotato
di sistema operativo Windows 98, basta scaricare il giusto download
dal sito www.apache.org
Con un doppio click si procedera' poi alla decompressione del file
ed alla istallazione standard di Apache, che verra' eseguita in
modo automatico.
Per la successiva configurazione di Apache, il file principale da
modificare e':
c:\Programmi\Apache Group\Apache\conf\httpd.conf
Vediamo com'e' strutturato tale file: intanto, ogni parametro
risulta ampiamente commentato sul file stesso, per rendere chiaro
il significato di quel parametro.
I parametri di configurazione piu' significativi da impostare sono:
1) ServerType:
2) Port 80:
Va lasciato impostato su standalone
Il valore di default e' 80, non conviene cambiarlo
3) HostnameLookups: Fa il Log dei nomi dei client (on) o solamente il
loro numero IP (off); lasciatelo pure su off
4) ServerAdmin:
E' inutile su un server locale ma se impostate il
vostro indirizzo e-mail, ad ogni errore Apache comunichera'
con voi come amministratore.
5) ServerRoot:
La directory dove Apache conserva i log, gli errori ed
i file di configurazione; di solito e':
c:\Programmi\Apache Group\Apache
6) LoadModule: Indica ad Apache quali moduli caricare; potete iniziare
senza variarlo (nessun modulo caricato) ma si possono poi
caricare anche tutti (l'avvio di Apache sara' piu' lento,
ma solo di qualche secondo).
Indispensabili per provare gli script saranno tutti i moduli per i CGI,
per il Perl e i mime.
7) ErrorLog:
File dove Apache scrive gli errori:
logs/error.log
puo' andare bene
8) ServerName:
Il nome del vostro server; se non l'avete mai impostato,
sara' "localhost.localdomain" ma, se volete cambiare il nome
al vostro host potete lanciare (da root) hostname e impostare
il nome dell'host.
9) DocumentRoot: La directory nella quale mettere i file html per la pagina
locale, solitamente
c:\Programmi\Apache Group\Apache\htdocs
Se in tale directory mettete un vostro index.html, indicando
'localhost' come indirizzo del browser, vedrete proprio questa
pagina e da questa partiranno le altre pagine.
10) DirectoryIndex: Il nome della pagina che verra' visualizzata come
indice, solitamente index.html
11) ScriptAlias: Se lo impostiamo ScriptAlias /cgi-bin/ /usr/lib/cgi-bin/
i nostri CGI saranno in /usr/lib/cgi-bin/, e saranno chiamati
tramite
http://localhost/cgi-bin/nome_cgi.cgi
12) AddHandler cgi-script:
Per gestire script CGI va impostato a
.cgi
A questo punto il server locale dovrebbe essere configurato e funzionante.
Se qualcosa non corrispondesse a queste istruzioni, potete riferirvi alla
documentazione, inclusa nell'archivio che avete scaricato nella cartella
/usr/doc/apache.
Per provare Apache avviare il browser ed accedere all'URL (index.html):
http://NomeHost
Il nome del vostro computer in rete e' visibile con
Risorse computer-->Pannello controllo-->Rete-->Identificazione
Nei dischetti delle esercitazioni sono presenti i files da trasferire
nella root-directory del sito c:\Programmi\Apache Group\Apache\htdocs
Con essi si potra' provare l'effetto dei marcatori HTML e di alcuni
script CGI.
Per avviare ed arrestare Apache si possono usare i due comandi seguenti
(a cui, per comodita' si possono far corrispondere due diverse icone):
"c:\Programmi\Apache Group\Apache\Apache.exe" -d
"c:\Programmi\Apache Group\Apache" -s
"c:\Programmi\Apache Group\Apache\Apache.exe" -d
"c:\Programmi\Apache Group\Apache" -k shutdown
⌡ 15.3 - PAGINE WEB DINAMICHE - CGI
-------------------------Esistono tre tipi di pagine Web:
1) STATICHE: sono quelle composte dal solo testo HTML; sono visualizzate
sempre nella stessa maniera.
2) DINAMICHE: sono pagine che possono variare ad ogni consultazione (come
quelle contenenti un contatore di accessi), in quanto vengono composte
in HTML dal Web server di volta in volta, prima di essere inviate al
client richiedente. Pero' una volta inviate non variano fino ad una
nuova consultazione sul server (aggiornamento).
3) ATTIVE: il contenuto della pagina viene reso variabile non da una
elaborazione del server, ma del client. Questo infatti riceve dal
Web server anche un programma che viene eseguito dal computer client,
mentre l'utente osserva il documento su video. Esempi sono le animazioni
o la visualizzazione di dati che devono essere continuamente aggiornati
come quelli di borsa.
Potendo i computer degli utenti essere diversi, e' indispensabile che
la tecnologia usata per scrivere questi programmi sia indipendente
dalla piattaforma.
A differenza delle pagine statiche, che chiunque e' in grado di scrivere
con un buon editor HTML, la scrittura di pagine dinamiche richiede una
certa capacita' di programmazione, che diventa ancora maggiore per le
pagine attive.
In quest'ultimo caso inoltre s'incontrano anche le problematiche della
sicurezza, dato che si importano programmi che vengono automaticamente
eseguiti sul computer client (si deve essere certi dell'affidabilita'
del mittente).
Nel server Web dev'essere istallata un'applicazione per ogni documento
dinamico e le sue impostazioni devono consentirgli di trovare (nella
giusta cartella) l'applicazione relativa al documento richiesto.
La tecnologia piu' diffusa per la composizione di questi documenti
dinamici e' lo standard CGI (Common Gateway Interface) e le applicazioni
si chiamano programmi CGI.
Lo standard CGI stabilisce le modalita' con cui vengono avviati i
programmi CGI e l'interpretazione del loro output.
I programmi CGI possono essere scritti nel linguaggio piu' conveniente
per programmare l'applicazione: per esempio se si devono fare molti
calcoli si puo' usare Fortran, C o C++ mentre se si deve solo comporre
testi si puo' usare il Perl o la shell del sistema operativo del server
ovvero l'interprete dei comandi (script CGI: contiene una sequenza di
comandi come quella che l'utente batterebbe manualmente al prompt della
finestra DOS, nel caso di Windows 98).
⌡ 15.3.1 - PASSAGGIO DI PARAMETRI AI PROGRAMMI CGI: FORM
--------------------------------------------I programmi CGI possono ricevere parametri in input, forniti dal server
o anche dal browser mediante l'aggiunta di un "?" seguito da un suffisso
alla stringa URL inviata al server. Per esempio si passa il parametro 5
cosi':
URL = http://www.sito.it/cgi/appl?5
(il prefisso identifica il documento dinamico, mentre tutto quanto segue
il "?" nella stringa URL viene passato come variabile locale chiamata
QUERY_STRING al programma CGI).
Altre variabili locali vengono passate dal server al programma CGI come,
per esempio:
SERVER_NAME = Nome di dominio del computer server
GATEWAY_INTERFACE = Versione del software CGI usato dal server
SCRIPT_NAME = Percorso dopo il nome del server nell'URL
REMOTE_ADDR = Indirizzo IP del computer client
I programmi CGI possono memorizzare informazioni tra due esecuzioni
successive in due modi:
- sul disco del server se la memorizzazione dev'essere permanente;
- nella stringa URL del documento, inserita come riferimento invisibile
all'utente nella pagina dinamica inviata al browser, se devono essere
memorizzate per una sola sessione (gli ritornera' indietro nell'URL
se l'utente clicca sul riferimento, per aggiornare la pagina).
Esempio:
<A HREF="http://www.sito.it/cgi/appl?5">
Clicca qui' per aggiornare la pagina.</A>
(il parametro 5 ritorna al programma CGI se l'utente clicca sul
riferimento mostrato dal browser).
Questa tecnica puo' essere usata nei programmi CGI per acquisire i dati
immessi dall'utente in un modulo appositamente predisposto (form) nella
pagina dinamica.
Per esempio, se l'utente immette il suo nome e l'eta' nel form, il browser
inserisce questi dati nell'URL:
http://www.sito.it/cgi/appl?NOME=Mario,ANNI=40
e cosi' possono arrivare al programma CGI che li utilizza.
⌡ 15.4 - PAGINE WEB ATTIVE: TECNOLOGIA JAVA
---------------------------------Per ottenere un aggiornamento continuo della pagina mostrata dal browser
si sono dapprima usate pagine dinamiche aggiornate di continuo dal server,
eseguendo continuamente il relativo programma CGI (tecnica server PUSH).
Questa soluzione e' insoddisfacente per il sovraccarico che produce sul
server.
La soluzione piu' soddisfacente e' quella di delegare al browser
l'aggiornamento della pagina, mediante l'esecuzione di un apposito
programma (applet) inviato dal server ed inserito nel codice HTML per
mezzo di appositi Tag, come nell'esempio seguente:
.........
<applet code="EsempioApplet.class" height=100 width=300>
</applet>
.........
dove EsempioApplet.class e' il file contenente il bytecode dell'applet.
Per ottenere l'indipendenza dalla piattaforma il linguaggio Java non
viene compilato nel codice di un particolare processore, ma in un codice
intermedio universale (bytecode), che viene eseguito da un interprete
(JVM, Java Virtual Machine) contenuto nei browser (scritti per tutte
le specifiche piattaforme).
Per usare le applet e' necessario conoscere il linguaggio di programmazione
Java (vedi prossimo capitolo).
Piccole applet, in forma sorgente, possono essere usate anche nel
linguaggio di script chiamato JavaScript. Le istruzioni dello script
(=copione) vengono eseguite dal browser, quando sono incontrate nella
pagina html. Con esse si puo' per esempio filtrare i dati immessi
dall'utente o riprodurre suoni da file audio.
⌡ 15.5 - ESEMPI DI JAVASCRIPT E SCRIPT CGI
--------------------------------Un esempio di uso di piu' JavaScript (eseguiti dal browser nella macchina
CLIENT) e di uno script CGI (eseguito dal Web server nella macchina SERVER,
quando richiesto dal client), si trova sul dischetto delle esercitazioni
nel file index.html. Questo file, che ora descriviamo, si trova nella
directory htdocs e costituisce un piccolo campionario dell'uso degli script:
--------------------- Inizio del file index.html ------------------------<!doctype html public "-//w3c//dtd html 4.0 transitional//en"> <!- Identifica
il tipo di documento ->
<html> <!- Tag di inizio codice HTML (case insensitive) ->
<!- Questi sono commenti ->
<head> <!- Tag di inizio intestazione ->
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"> <!Attributi del documento ->
<title>Pagina di prova dell'installazione di un sito Web con Apache</title>
</head> <!- Tag di fine intestazione ->
<!- Tag di inizio parte principale (corpo) del documento ->
<body text="#000000" bgcolor="#FFFFFF" link="#0000FF" vlink="#000080"
alink="#FF0000">
<center><h1> <! Height 1 (=max) dei caratteri (titolo, allineato al centro) >
Apache funziona!
</h1></center>
<BR> <!- Tag di Ritorno a capo ->
Cominciamo ora a vedere all'opera: un CGI (eseguito da Perl sul Server) e
due JavaScript (eseguiti dal browser sul Client).
<p> <!- Tag di nuovo Paragrafo ->
Esempio N.1 (Link a CGI): Il CGI, contenuto nel file Esempio2.cgi, viene
eseguito solo se si clicca sul link seguente:
<a href="http://127.0.0.1:80/cgi-bin/Esempio2.cgi"> Prova script CGI </a>
<p align=left> <!- Esempio di paragrafo allineato a sinistra ->
Esempio N.2 (un JavaScript esterno): E' stato scritto in index.html il
richiamo
al JavaScript contenuto nel file prova.js (scritto con Blocco Note), che
produce un avviso con il comando seguente:
alert('Avviso prodotto dal primo JavaScript (esterno)');
<SCRIPT SRC="prova.js"></SCRIPT>
<p align=right> <!- Esempio di paragrafo allineato a destra ->
Esempio N.3 (due JavaScript interni): E' stato scritto direttamente in
index.html
il codice HTML di due JavaScript che producono gli avvisi N.1 e N.2
<SCRIPT Language="Javascript">
x=1; alert('Avviso N.'+x+' prodotto dal secondo JavaScript (interno)');
</SCRIPT>
<SCRIPT Language="Javascript">
x++; alert('Avviso N.'+x+' prodotto dal secondo JavaScript (interno)');
</SCRIPT>
<p> <!- Esempio N.4: JavaScript eseguito al verificarsi di un evento
(onmouseover) ->
<a href="#" onmouseover="alert('OK, ci sei passato')">Esempio JavaScript N.4
(Evento): viene eseguito se passi qui sopra</a>
<p> <!- Esempio N.5: JavaScript eseguito al posto di un link ->
<a href="javascript:alert('JavaScript eseguito al Click (come un
link)')">Esempio JavaScript N.5 (Link): viene eseguito solo se clicchi
qui</a>
<p>
<HR> <!- Linea orizzontale ->
<BIG> <!- Inizia testo grande ->
<b>Arrivederci!</b> <!- Scritta in grassetto ->
</BIG>
</body> <!- Tag di fine parte principale (corpo) del documento ->
</html> <!- Tag di fine codice HTML ->
--------------------- Fine del file index.html ------------------------Scaricando questa pagina con un browser, sul vostro computer (dopo aver
avviato il Web server Apache) con http://localhost/index.html si ottengono
tre messaggi prodotti dai tre Javascript (in esempio N.2 ed esempio N.3) e
viene visualizzata poi la pagina index.html.
Il primo messaggio (in esempio N.2) e' prodotto con il file prova.js
richiamato nella riga seguente:
<SCRIPT SRC="prova.js"> </SCRIPT>
Questo file (prova.js) contiene uno script (esterno), composto dalla sola
riga seguente (che produce il messaggio di avviso):
alert('Avviso prodotto dal primo JavaScript (esterno)');
Gli altri due script in esempio N.3 (interni alla pagina html) producono
due messaggi, con incremento di una variabile x:
<SCRIPT Language="Javascript">
x=1; alert('Avviso N.'+x+' prodotto dal secondo JavaScript (interno)');
</SCRIPT>
.........
<SCRIPT Language="Javascript">
x++; alert('Avviso N.'+x+' prodotto dal secondo JavaScript (interno)');
</SCRIPT>
La pagina html contiene anche il seguente link allo script CGI contenuto
nel file Esempio2.cgi (in esempio N.1), situato nella directory cgi-bin
del server:
<a href="http://127.0.0.1:80/cgi-bin/Esempio2.cgi"> Prova script CGI </a>
Quando nel browser si clicca sul link, il Web server Apache viene comandato
di eseguire lo script CGI, che invoca l'interprete Perl e prepara una nuova
pagina html, eseguendo le istruzioni di print nello script.
Questa nuova pagina viene poi inviata al browser, che la visualizza.
Lo script CGI, contenuto nel file Esempio2.cgi, e' il seguente:
#!/Perl/bin/perl
print "Content-type:text/html\n\n";
print "<html><head><title>Prima pagina di prova</title></head>\n";
print"<body>\n";
print"Esempio di CGI: questa pagina e' stata confezionata da Esempio2.cgi,
interpretato da Perl sul Web server, ed inviata al client che la sta
ora visualizzando con il browser.";
print "<h2>Ciao a tutti!</h2>\n";
print "Se volete, potete tornare alla pagina precedente con Back";
print"</body></html>\n";
Questo script CGI e' quindi eseguito sul server, a differenza dei due
JavaScript precedenti, che venivano eseguiti sul client.
Nell'esempio N.4 c'e' un JavaScript, che viene pero' eseguito solo al
verificarsi di un evento (onmouseover=passaggio del mouse sopra alla
scritta).
Nell'esempio N.5 e' contenuto un altro JavaScript: in questo caso viene
eseguito solo se si clicca sulla sua scritta (come fosse un link).
!----------------------------------------------------------------------CAPITOLO 16 - Architetture avanzate
═══════════
Riassunto: In questo capitolo viene data una classificazione dei sistemi
di elaborazione parallela e ne vengono discussi gli elementi
alla base del loro sviluppo..
(.... scrittura dispense in corso: vedi Fotocopie ....)
Classificazione SISD, SIMD, MISD, MIMD
Complessita' collegamenti, crossbar switch, ecc.
!----------------------------------------------------------------------CAPITOLO 17 - Acquisizione di dati sperimentali
═══════════
Riassunto: Scopo essenziale di questo capitolo e' quello di introdurre
le problematiche connesse al controllo automatico degli
apparati sperimentali ed all'acquisizione dei dati (on-line).
Dopo l'introduzione degli standard NIM, CAMAC, VME e FASTBUS
si discutono i sistemi si elaborazione parallela multiprocessore.
⌡ 17.1 - ACQUISIZIONE DEI DATI SPERIMENTALI
==================================
La fisica si occupa di scoprire e studiare le leggi fisiche della
Natura ovvero i rapporti quantitativi che intercorrono tra le grandezze
osservabili, cioe' suscettibili di misurazione e quindi quantificabili
con numeri: per questo, come la matematica ed i calcoli numerici hanno
un ruolo fondamentale in fisica, cosi' anche i calcolatori elettronici
sono fondamentali per i fisici come strumenti di calcolo (uso OFF-LINE).
║
Inoltre i calcolatori elettronici sono anche l'elemento centrale di
analisi e controllo in linea (uso ON-LINE) di tutti i moderni apparati
sperimentali e vanno quindi visti come parte essenziale dello strumento
con cui il fisico misura le grandezze fisiche osservabili, che sono
oggetto di studio della fisica sperimentale.
Cosi' per i fisici lo studio dei calcolatori elettronici e dei loro campi
e modalita' di impiego deve essere associato allo studio degli altri
elementi che concorrono a formare l'apparato sperimentale, con cui
indaghiamo il mondo fisico, che sono:
1) i trasduttori delle informazioni fisiche (per esempio i rivelatori di
particelle);
2) gli strumenti che si usano per misurare le grandezze fisiche osservate
dai trasduttori;
3) le metodologie di acquisizione ed analisi dei dati forniti dagli strumenti, in cui e' fondamentale l'impiego dei calcolatori elettronici.
I calcolatori elettronici sono quindi usati, oltre che per la raccolta e
l'analisi dei dati sperimentali, anche per l'automazione dell'esperimento.
Le problematiche relative al loro uso sono comuni a tutte le applicazioni
di questo tipo. Per capirle piu' completamente consideriamo il caso degli
apparati sperimentali piu' complessi, quelli usati nella fisica delle
particelle elementari. In questi esperimenti capita che il flusso di dati
fornito dall'apparato sia troppo elevato per essere raccolto integralmente dal sistema di computers. Cio' accade perche' nei dati sono presenti
molti eventi 'di fondo', cioe' non interessanti per la fisica in studio
o addirittura errati ('rumore').
E' necessario allora aggiungere all'apparato sperimentale un sistema di
filtraggio hardware, chiamato Trigger, che blocchi questi eventi spuri
prima che arrivino al sistema di acquisizione computerizzato, lasciando
passare solo gli eventi d'interesse, che devono essere in quantita'
minore o uguale della massima gestibile dal sistema di computers.
Mentre in un'oscilloscopio il trigger e' la condizione che fa partire
lo 'sweep' orizzontale (la manopola regola la soglia in ampiezza che
costituisce la condizione), qui' il trigger e' la condizione che fa
partire l'acquisizione dei dati.
⌡ 17.1.1 - UN SEMPLICE ESEMPIO DI ACQUISIZIONE DI DATI SPERIMENTALI
========================================================
Siccome agli studenti non risulta immediatamente comprensibile cosa
significhi un sistema di trigger in un apparato sperimentale complesso,
presentiamo un semplice esempio che aiuta a capire meglio questo
argomento.
Il sistema di trigger che presentiamo si riferisce ad un ipotetico
esperimento, in cui si vogliono separare i mesoni μ dai mesoni ⌠,
misurandone la velocita' ß ed il momento p.
Progettiamo l'apparato sperimentale indicato in figura (dove sono usati
deliberatamente i termini inglesi internazionalmente usati dai fisici)
in base ai seguenti criteri:
1) Per determinare la velocita' ß misuriamo il tempo di volo tra i
contatori a scintillazione S1 ed S2 con uno strumento TAC (Time
to Amplitude Converter), che misura l'intervallo di tempo tra gli
impulsi prodotti da S1 ed S2 (gli impulsi elettrici sono prodotti
da un fotomoltiplicatore che raccoglie la luce prodotta dagli atomi
dello scintillatore nel decadimento dai livelli eccitati dal
passaggio del mesone carico).
2) Per determinare l'angolo di scattering ed il momento p del mesone
misuriamo il raggio di curvatura del percorso del mesone nel campo
magnetico, a partire dai tre punti di attraversamento delle camere
a fili C1, C2 e C3 (le camere a fili sono rivelatori che permettono
questa localizzazione; il campo magnetico, grazie alla forza di
Lorentz, produce una curvatura del percorso che e' funzione del
momento p e quindi ci permette di misurarlo).
3) Per separare i mesoni μ dai ⌠ aggiungiamo un blocco di ferro di
spessore superiore al range dei mesoni ⌠ (che quindi non riescono ad
attraversarlo), ma inferiore al range dei mesoni μ (che passeranno
poiche', non interagendo nuclearmente con l'assorbitore, sono piu'
penetranti). Lo scintillatore S3 quindi dara' un segnale nel caso di
un mesone μ, mentre non dara' alcun segnale nel caso di un mesone ⌠.
(angolo di scattering=teta)
╔══════════════╗
┌┐
|
/
║
____________╔═╗....││..............|
/
║
Beam μ ⌠
╚═╝
││
⌠
|
/ C2
║<── Campo magnetico
(fascio)
Target
└┘
C1|
/
║
(bersaglio) S1
|
/
║ (curva la traiettoria)
║
/
║
S1,S2,S3 = Scintillatori
╚═╗
C3
║
╚═ ----:--- ═╝
C1,C2,C3 = Camere a fili
:
:⌠
CAMPO MAGNETICO: misura p,teta
S2 ┌─────:─────┐ (Coincidenza)
TEMPO DI VOLO : misura ß
└─────:─────┘
ANTICOINCIDENZA: separa μ da ⌠
╔════════:════════╗
║ Assorbitore Fe ║<── Arresta i ⌠
╚═════════════════╝ Non arresta i μ
┌───────────┐
S3 └───────────┘ (Anticoincidenza)
La logica di trigger in questo esperimento quindi sara':
__
LOGICA DEL TRIGGER:
Evento ⌠ = S1.S2.S3
Evento μ = S1.S2.S3
Schema di montaggio dei moduli standard NIM (risoluzione 0.1 nsec):
S1 ┌──────────┐
────>│Ritardo D1│────┐ ╔═══╗
( Moduli NIM )
└──────────┘
└─>║AND║────┐
S1 ┌──────────┐
┌─>╚═══╝
│ ╔═══╗
────>│Ritardo D2│────┘
└─>║AND║────> SEGNALE DI TRIGGER ⌠
└──────────┘
╔═══╗
┌─>╚═══╝
(anticoincidenza
S3)
───────────────────────>║NOT║────┘
S3
╚═══╝
I ritardi D1 e D2 sono inseriti per mettere in tempo i segnali all'ingresso
delle coincidenze AND all'istante T (vedi schema seguente).
Temporizzazione dei segnali:
|<-------------- D1 --------------->|
S1 ───────────┐
┌────────────────────────────────────────
└───┘
|<--D2-->|
S2 ──────────────────────────────────────┐
┌─────────────
└───┘
|
S3 ───────────────────────────────────────────────┐
┌────
└---┘
T
⌡ 17.1.2 - SISTEMA DI ACQUISIZIONE DEI DATI SPERIMENTALI
=============================================
Questo filtraggio degli eventi (Trigger) viene realizzato in un primo
stadio con semplici sistemi elettronici in logica combinatoria fatta
con moduli standard NIM, particolarmente veloci, come quello mostrato
in figura. La semplicita' delle funzioni sintetizzate non consente
pero' di essere selettivi al massimo, per cui e' possibile che con
questi sistemi di trigger non si riesca ad abbassare a sufficienza il
flusso (rate, numero di eventi al secondo) dei dati verso il sistema
dei computers che devono acquisirli.
Si usa allora, sul flusso di dati gia' ridotto dal sistema di trigger
primario, un sistema hardware di trigger secondario che, realizzando
funzioni logiche piu' complesse (anche se in modo un poco piu' lento),
assicura un ulteriore fattore di riduzione del flusso dei dati, portandolo
ad un livello sopportabile dal sistema di computers.
I computers montati in linea (ON-LINE) con l'apparato di acquisizione dei
dati possono a questo punto assicurare un ulteriore fattore di riduzione
dei dati mediante algoritmi software, lasciando registrare su supporto
magnetico (per le successive elaborazioni piu' sofisticate al centro di
calcolo) solo gli eventi interessanti, depurati da gran parte degli eventi
di fondo che erano presenti in origine.
Lo schema di funzionamento dell'intero sistema di acquisizione-dati di un
esperimento di fisica delle alte energie (cioe' del supermicroscopio con
cui i fisici scrutano il mondo subnucleare) puo' cosi' essere rappresentato
con lo schema seguente:
┌───────────────┐
│ Eventi Fisici │
└───────┬───────┘
┌─────┴──────┐
│ Rivelatori │
└──┬──┬──┬───┘
┌──────┴──┴──┴────────┐ Reset
│ Strumenti di misura ├<──────────┐
└───┬─────┬─────┬───┬─┘
│
│
│ ┌───┴───┴────────┐ No │
│
│ │Trigger primario├───>┤ F
│
│ └───────┬────────┘
│ I
│
│
│OK
│ L
│ ┌──┴─────────┴─────┐ No
│ T
│ │Trigger secondario├──────>┤ R
│ └────────┬─────────┘
│ A
│
│OK
│ G
╔═══╩═══════════╩═════╗
│ G
I blocchi
║ Acquisizione Evento ║
│ I
╚══════════╦══════════╝
│ O
a tratto doppio
║
│
╔══════╩══════╗ No
│
rappresentano
║ Preanalisi ╠──────────────>┘
╚══════╦══════╝
il software
║OK
╔══════════════╩═══════════════╗
( ON-LINE )
║
Analisi completa +
║
║
Monitoraggio esperimento
║
╚══╦═══════════╦════════════╦══╝
│ ┌────────┴─────────┐ │
│ │Supporti magnetici│ │
│ └────────┬─────────┘ │
│ ╔════════╩═════════╗ │
Software (OFF-LINE) ---> │ ║Centro di calcolo ║<─┘
│ ╚════════╦═════════╝
│ ┌────────┴─────────┐
└─>│
U O M O
│
└──────────────────┘
Altri compiti del sistema di computer on-line sono:
1) selezionare e comprimere i dati sperimentali prima di
memorizzarli
sul supporto magnetico;
2) eseguire in tempo reale tutti i controlli sulla correttezza di funzionamento dell'apparato (monitoraggio);
3) fornire ai fisici di turno tutti gli 'output' necessari a valutare
l'andamento dell'esperimento;
4) di assicurare la connettivita' del sistema verso l'esterno.
Le strategie di gestione software sono molteplici e dipemdono dalle
peculiarita' dell'esperimento.
⌡ 17.1.3 - UN ESEMPIO DI SISTEMA DI ACQUISIZIONE DATI
==========================================
Per aiutare lo studente a comprendere meglio le problematiche della
gestione software di un sistema di acquisizione dati on-line, riportiamo
un semplice esempio di organizzazione possibile dei compiti descritti nel
paragrafo precedente e' riportato nello schema seguente:
PRIORITA':
┌─────────────────>┐
│
┌───────┴────────┐
Interrupt da livelli
inferiori
Alta
│
│ ACQUISIZIONE │ (Legge e accoda nuovo evento)
(foreground) │
└───────┬────────┘
│
│(fine acquisizione)
│
│
│ interrupt┌───────┴────────┐ Analizza tutti eventi in coda
Intermedia │<─────────┤
ANALISI
│ (filtraggio software)
(foreground) │
└───────┬────────┘
│
│(coda vuota)
│
│
│ interrupt┌───────┴────────┐ Spende il tempo restante in
Bassa
└<─────────┤
BACKGROUND
│ compiti di monitoraggio, ecc.
(background)
└────────────────┘
Questo schema e' realizzabile organizzando le priorita' delle interruzioni
su vari livelli, in cui il trigger degli eventi fisici occupa uno dei
livelli piu' alti.
Il suo funzionamento puo' essere descritto cosi':
- L'interrupt di un evento fisico forza il computer ad andare in
ACQUISIZIONE, leggendo i dati dell'evento dagli strumenti ed
inserendoli nella coda degli eventi da analizzare.
- Terminata l'acquisizione, il controllo viene passato ai programmi
di ANALISI che elaborano tutti gli eventi in coda (eventualmente
scartandoli), interrompendosi all'arrivo di un nuovo evento (le
interruzioni di livello piu' basso restano disabilitate: per questo
i livelli di ACQUISIZIONE e ANALISI costituiscono la piattaforma di
lavoro piu' prioritaria 'Foreground' rispetto al 'Background').
- Terminata l'analisi (coda vuota) il controllo passa ai programmi
di BACKGROUND, dove il computer spende tutto il tempo 'libero',
con tutte le interruzioni abilitate.
Come esempio riportiamo l'impostazione delle priorita' delle varie
interruzioni in un sistema di acquisizione on-line, effettivamente
realizzato in un esperimento di fisica:
Priorita' int. Sorgente interrupt
Commento
----------------------------------------------------------------------1
Output su nastro magn.
Output disabled blocca acquisiz.
2
Counters, R.T.Clock
Immediate reset if counter Overflow
3
Trigger eventi fisici
Questo avvia l'acquisizione+analisi
4
Refreshing display
Esempio di attivita' meno prioritaria
5
Console input
Idem (ma input prioritario su output)
6
Console output
Ecc.
Al livello Background un'impostazione possibile della supervisione dei
compiti da eseguire puo' essere rappresentato dallo schema seguente
(i compiti eseguiti, o task, vanno programmati dall'utente secondo le
esigenze del suo specifico esperimento):
┌───────────────────>┐ (Loop continuo)
│
│
│
╔════════════════╩═════════════╗ No
│
║ Ricevuto comando da utente ? ║───────>┐
│
╚════╦═══════╦═══════════╦═════╝
│
│
│
│
│Si
│
│
┌──┴──┐ ┌──┴──┐
┌──┴──┐
╔═══════╩════════╗ Si
│
│Task1│ │Task2│.....│TaskN│
║ Controllo HV ? ║────────>┐
│
└──┬──┘ └──┬──┘
└──┬──┘
╚═══════╦════════╝
┌───────┴────────┐
├<───────┴───────┴───────────┘
No│
│Esegue
controllo│
│
Task singoli
│
└───────┬────────┘
│
(eseguiti una tantum)
│<─────────────────┘
│
╔═══════╩════════╗ Si
│
║Refresh display?║────────>┐
│
╚═══════╦════════╝
┌───────┴────────┐
│
No│
│ Esegue refresh │
│
│
└───────┬────────┘
│
LIVELLO BACKGROUND
│<─────────────────┘
│
==================
|
│
|
(Task ripetitivi)
│
|
│
╔═══════╩════════╗ Si
│
║Garbage collect?║────────>┐
│
╚═══════╦════════╝
┌──────┴──────┐
│
No│
│ Esegue G.C. │
│
│
└──────┬──────┘
└<──────────────────────────────────────────┘<─────────────────┘
Il computer spende tutto il suo tempo libero nel loop in cui esegue
ripetitivamente una serie di compiti (i task ripetitivi), ognuno
controllato da un apposito flag di attivazione impostabile dall'utente
(se il flag e' off il task non viene eseguito).
Tra i task ripetitivi c'e' l'esame del buffer di input dei comandi.
Se un comando viene ricevuto, il corrispondente task viene eseguito una
sola volta (sono i task singoli).
Il numero di task inseribili nelle due categorie risulta praticamente
illimitato.
⌡ 17.2 - GLI STANDARD DI STRUMENTAZIONE ELETTRONICA
==========================================
Negli anni '50 i vari laboratori nazionali si costruivano autonomamente
l'elettronica necessaria per fare la selezione dei dati finora descritta,
accumulando cosi' negli anni un patrimonio di know-how e di strumentazione
costruita.
Negli anni '60 pero' ci si accorse che in occasione di collaborazioni
internazionali si avevano dei seri problemi ad usare contemporaneamente
nello stesso esperimento strumenti costruiti da laboratori diversi con
standard (meccanici, elettrici, funzionali, ecc.) diversi.
Si comincio' cosi' a studiare uno standard unico che potesse essere
accettato da tutti e che risolvesse i problemi di acquisizione-dati
previsti per gli anni futuri, compreso quello di consentire l'interfacciamento al computer di un grande numero di strumenti.
Il risultato di questi studi fu, dopo lo standard NIM per l'elettronica
combinatoria veloce (discriminatori, TAC, AND, OR, NOT, ecc. da usare
nel sistema di trigger), lo standard CAMAC per la strumentazione di
acquisizione dei dati (convertitori ADC/TDC, scale di conteggio, pattern
units, ecc.).
Lo standard CAMAC , introdotto dal comitato europeo ESONE nel 1969, si
proponeva quindi di risolvere i seguenti problemi:
1) Standardizzazione dell'interfacciamento della strumentazione;
2) Espansione delle capacita' di interfacciamento del computer.
Il documento ufficiale di riferimento, contenente documentazione e
specifiche e':
CAMAC: Sistema modulare di strumentazione per l'elaborazione dei dati
( Documento C.E.E. - EUR 4100 - 1970 )
Successivamente, negli anni '80, per superare le prestazioni del CAMAC,
sono stati introdotti gli standard VME (TTL) e FASTBUS (praticamente
in tecnologia ECL), capaci di ospitare anche piu' CPU e memorie per
l'elaborazione distribuita.
Per capire meglio come vengono usati questi standard, osserviamo
lo schema seguente, in cui risultano evidenziati i blocchi che li
utilizzano:
┌───────────────┐
│ Eventi Fisici │
└───────┬───────┘
┌─────┴──────┐
│ Rivelatori │
└──┬──┬──┬───┘
│ │ │
╔══════╩══╩══╩════════╗ Reset
5 ns ║
Standard NIM
║<─────────┐ T
I blocchi
╚═══╦═════╦════╦════╦═╝
│ R
│ ┌──┴────┴────┴─────┐ No
│ I
a tratto doppio
│ │Hardware Processor├─────>┤ G
│ └────────┬─────────┘
│ G
indicano
│
│OK
│ E
╔═══╩═══════════╩═════╗ No
│ R
gli standard
50 ns ║Standard FASTBUS/VME ║─────────>┘
╚═══════════╦═════════╝
NIM,FASTBUS,VME,CAMAC
│
╔══════════╩═════════╗
1000 ns ║ Standard CAMAC/VME ║
╚══════════╦═════════╝
│
┌──────────────┴───────────────┐
( ON-LINE )
│
HOST COMPUTER
│
└──┬───────────┬────────────┬──┘
│ ┌────────┴─────────┐ │
│ │Supporti magnetici│ │
│ └────────┬─────────┘ │
│ ┌────────┴─────────┐ │
( OFF-LINE )
│ │Centro di calcolo │<─┘
│ └────────┬─────────┘
│ ┌────────┴─────────┐
└─>│
U O M O
│
└──────────────────┘
⌡ 17.2.1 - LO STANDARD CAMAC
=================
Il CAMAC e' uno standard di strumentazione nato al CERN, che stabilisce
regole uniformi per la costruzione e l'interconnessione degli strumenti
di uso comune nella fisica sperimentale.
Esso consente ad un host computer di accedere agli strumenti contenuti
in un 'crate' (contenitore meccanico degli strumenti, altrimenti detto
'cassa CAMAC'), compiendo su di essi operazioni di I/O.
Un crate CAMAC puo' contenere 23 moduli (=cassettini) di strumentazione,
indirizzabili dall'host computer con un numero di stazione N (=1..23).
Oognuno di questi moduli puo' contenere fino a 16 strumenti, indirizzabili
con un sub-address A (=0..15).
L'interfacciamento e' realizzato in TTL, attraverso un modulo master a
doppio slot, chiamato controller, e da un'elettronica digitale slave in
ogni modulo, in comunicazione sincrona con il master con ciclo di 1μs.
Con questa comunicazione master-slave si realizza il multiplexaggio
dell'I/O bus del computer sui 23x16 strumenti, consentendo il collegamento
individuale di ogni strumento al computer.
Il prezzo che si paga per ottenere questo ampliamento delle capacita' di
I/O del computer e' che l'operazione di I/O CAMAC avviene in due passi:
1) Impostazione di indirizzo e comando nei registri del controller;
2) Esecuzione dell'operazione di I/O (sul registro D del controller).
Lo schema di collegamento e' riportato nello schema seguente:
╔═════════════════╗
║ HOST COMPUTER ║
╚════════╦════════╝
I/O port║
║
<------------------ Crate CAMAC ----------------->
║ ╔═══╗N,A,F┌───┬────────────┐
Computer║ ║
║════>┤ C │ Controller │
DATAWAY (ciclo=1μs)
╠══╣I/F║
├───┤
├═════╦═════ ═ ═ ═ ═ ══════╗
I/O bus ║ ║
║<═══>┤ D │
CAMAC
│
┌─┴──┐
┌──┴─┐
║ ╚═══╝ R,W └───┴────────────┘
│ S1 │
│ S1 │
║
│ .. │ ............ │ .. │
|
Fino a 16 strumenti --->│ .. │
│ .. │
|
(ogni modulo)
│ S16│
│ S16│
|
└────┘
└────┘
|
C,D=Registri del controller
N=1
N=23
|
R,W=Linee Read/Write
<--- Fino a 23 moduli --->
N,A,F=Linee di comando
(ogni crate)
I/F e' il circuito di interfacciamento del modulo controller (standard
CAMAC) con l'I/O bus (proprietario) dello specifico computer.
In questo schema si deve usare un circuito I/F per ogni crate; in realta'
si puo' costruire I/F nello stesso controller, rendendolo cosi' specifico
per quel tipo di computer.
Lo standard CAMAC prevede anche l'uso di un solo circuito I/F, che
interfaccia l'I/O bus del computer con uno speciale bus standard CAMAC,
simile al dataway e chiamato branch highway, che permette il collegamento
di un numero massimo di 8 crates su un solo I/O port del computer.
In tal caso lo schema di collegamento e' il seguente:
╔═════════════════╗
║ HOST COMPUTER ║
╚════════╦════════╝
I/O port║
║
Computer║
I/O bus ║
╔═╩═╗
║I/F║
<------------------ Crate CAMAC ------------------>
╚═╦═╝
┌──────────────────┐
║N,A,F│ Controller CAMAC │
DATAWAY (ciclo=1μs)
╠═════┤
┌───┬───┐
├═════╦═════ ═ ═ ═ ═ ══════╗
CAMAC ║ R,W │
│ C │ D │
│
┌─┴──┐
┌──┴─┐
BRANCH ║
└─────┴───┴───┴────┘
│ S1 │
│ S1 │
HIGHWAY║
│ .. │ ............ │ .. │
║
Fino a 16 strumenti --->│ .. │
│ .. │
║
(ogni modulo)
│ S16│
│ S16│
║
└────┘
└────┘
|
N=1
N=23
|
|
|
|
<---- Fino a 23 moduli --->
..... ECC. (FINO A 8 CRATES SULLO STESSO BRANCH HIGHWAY)
Per la comunicazione sul dataway i progettisti hanno riservato:
N (Numero del modulo): una linea individuale di indirizzamento per ogni
modulo, per un totale di 24 linee individuali
(dirette dal controller ai moduli);
L (Look-at-me): una linea individuale di richiesta di attenzione per ogni
modulo, per un totale di 24 linee individuali
(dirette dai moduli al controller);
A (sub-Address): 4 linee omnibus per l'indirizzamento dei 16 strumenti
all'interno di un modulo;
F (Funzione): 5 linee omnibus per la codifica della funzione da eseguire
sullo strumento indirizzato
R,W (Read/Write): 24+24 linee omnibus per lo scambio di dati tra modulo
e controller.
La struttura del dataway e' indicata nello schema seguente:
Linee Omnibus F,A,R,W
╔══════ ═ ═ ═ ═ ═══════╦════════╦════════╗
║ ┌─────────<──────────║────────║────────║────┐
║ │
.................║........║........║....│
║ │ Linee individuali: ║ ┌──<───║────<───║──┐:│
║ │ N=da CS a moduli ║ │ N
║ ┌──<───║─┐│:│
┌┴─┴┐ L=da moduli a CS ┌┴─┴┐
┌┴─┴┐ N ┌┴─┴┴┴┴┐
│S1 │
│S1 │
│S1 │
│ C S │
│.. │ .............. │.. │
│.. │
│ O T │
│.. │
│.. │
│.. │
│ N A │
│.. │
│.. │
│.. │
│ T T │
│.. │
│.. │
│.. │
│ R I │
│.. │
│.. │
│.. │
│ O O │
│S16│
│S16│
│S16│
│ L N │
└───┘
└───┘
└───┘
└──────┘
N=1
N=23
N=24
CS
<---- Fino a 23 moduli ---->
<-- Controller-->
Le linee omnibus collegano i pin corrispondenti su TUTTE le stazioni
(N=1..24).
Le linee individuali collegano la stazione di controllo alle stazioni
(slot) dei singoli moduli:
- 24 linee N (select), dirette dal controller verso i moduli, usate per
selezionare il modulo a cui e' diretto il comando;
- 24 linee L (Look-at-me), dirette dal modulo al controller, usate per
chiedere attenzione (interrupt) al computer.
Il registro C del controller deve contenere un comando composto da
N,A,F per 14 bit complessivi, impacchettati nel modo stabilito dal
costruttore del controller.
Il registro D e' dedicato alla memorizzazione temporanea del dato da
trasferire sul dataway.
Se l'I/O port a cui e' connessa l'interfaccia CAMAC (I/F) e' sugli
indirizzi C100H per il dato e C101H per il controllo, lo schema di
programmazione di input ed output su CAMAC e' il seguente:
Operazione di input
------------------LDA# NAF
STA C101H
LDA C100H
........
Operazione di output
-------------------LDA# DATO
STA C100H
LDA# NAF
STA C101H
........
Il ciclo CAMAC di trasferimento del dato sul Dataway viene avviato dal
controller al termine dell'istruzione STA C101H (invio del comando al
controller). E' un ciclo sincrono con due segnali di strobe S1 e S2,
che permettono, per esempio, di leggere (S1) ed azzerare (S2) uno
strumento dello stesso ciclo CAMAC.
Il ciclo dura 1μs, secondo lo schema temporale che segue.
DATAWAY TIMING:
<---------- Ciclo CAMAC (1μs) ---------->
|
|
|
|
|
|
Commando e Busy ──────┐
|
|
|
|
┌────
(N,A,F,B)
└───────────────────────────────────────┘
|
|
|
|
|
|
Dati (R,W) ────────┐
|
|
|
|
┌────
└───────────────────────────────────────┘
|
|
|
|
|
|
Strobe S1 ────────────────────────────┐
┌────────────────────
|
|
└───────┘
|
|
|
|
|
|
|
|
Strobe S2 ────────────────────────────────────────┐
|
┌────────
|
|
|
|
└───────┘
|
| 200ns | 200ns | 200ns | 200ns | 200ns |
Dopo il ciclo CAMAC di 1μs, il dato e' stato recapitato:
1) nel primo caso (input) sul registro D del controller e puo' quindi
essere prelevato subito dopo con l'istruzione LDA C100H;
2) nel secondo caso (output) nello strumento indirizzato (modulo N,
sub-address A.
Per quanto riguarda le richieste di interruzione da parte degli
strumenti CAMAC, tenendo presente che tutte quelle provenienti da un
crate afferiscono ad un unico I/O port del computer, i progettisti
hanno riprodotto all'interno del CAMAC uno schema di priorita' analogo
a quello con cui vengono gestite le richieste d'interruzione delle
periferiche all'interno del computer: anche in quel caso infatti
devono essere tutte ricondotte (con un OR gerarchico) ad un unico
input nell'unita' centrale CPU.
Lo schema e' quindi:
<---------- Moduli CAMAC --------->
┌─────────┐
┌─────────┐
│ │ ┌─ F2│
│ │ ┌─ F2│
│ ╔╩═╩╗
│
│ ╔╩═╩╗
│
CONTROLLER CAMAC
│ ║AND║
│-- - - - - - │ ║AND║
│
┌─────────────────────┐
│ ╚═╦═╝
│
│ ╚═╦═╝
│
│
F1
│
└───│─────┘
└───│─────┘
│ ╔════╗ │
╔════╗ │
│
└─────────────>║
║ └──>║
║ │
│
..............│..║ OR ╠─────>║ AND╠────┐
└─────────────────────────────────────>║
║
║
║ │
│ ╚════╝
╚════╝ │ │
└─────────────────────┘ │
<----------------------- Crate CAMAC -------------------------> │
|
|
┌──────────────┐
|
│
F
╔════╗ │
│
PERIFERICA │
└──>║
║ │
│
DEL
│ ────>║ AND╠───────┤
COMPUTER
│ Done ║
║ │
│
│
╚════╝ │
│
└──────────────┘
│
│
- - - - - - - │
│
│
COMPUTER
┌─────────│───┐
│
F0──┐ │
│
│
╔╩═╩╗ │
│
║AND║ │
│
╚═╦═╝ │
└────────│────┘
│
Interrupt
*********
I flip-flop F0,F1,F2, impostabili con normali comandi CAMAC, costituiscono
i bit di mascheramento, che agiscono a vari livelli gerarchici:
1) F0 blocca tutte le interruzioni;
2) F1 blocca tutte le interruzioni di un crate CAMAC;
3) F2 blocca le interruzioni di un modulo; appositi moduli (LAM grader
consentono di pilotare anche le interruzioni dei singoli strumenti).
⌡ 17.2.2 - LO STANDARD VME
===============
Il CAMAC con il suo ciclo di 1μs risulto' presto inadeguato a fronteggiare
il rapido sviluppo delle esigenze della fisica sperimentale condotta ai
grandi acceleratori di particelle elementari.
Il primo accorgimento piu' semplicemente realizzabile con l'esistente
(CAMAC) e' stato quello di sfruttare il parallelismo intrinseco nelle
procedure di acquisizione dati impegnando piu' processori in parallelo,
ognuno collegato a diversi crate CAMAC o anche inserendo microprocessori
all'interno dei controller CAMAC.
Quando anche questi sistemi risultarono insufficienti per trattare in
linea l'accresciuto flusso di dati dall'apparato sperimentale, divento'
evidente la necessita' di progettare dei sistemi standard di prestazioni
superiori a quelle del CAMAC.
Le idee che furono alla base della progettazione dei nuovi standard (VME
e Fastbus) sono:
1) Consentire a piu' di un master di operare sull'interconnessione,
mentre nel dataway CAMAC c'e' un solo master: il controller (questa
caratteristica viene indicata con il termine inglese Multimastership).
2) Comunicazione asincrona, per permettere l'esecuzione di transazioni
alla massima velocita' possibile: con la sincronizzazione handshake
tra i moduli master e slave il ciclo dura meno se i moduli sono veloci,
mentre dura di piu' se i moduli sono piu' lenti (perche' si attendono
a vicenda).
Si e' cosi' arrivati all'introduzione dei due nuovi standard VME (in TTL)
e Fastbus, ancora piu' veloce (perche' puo' lavorare in ECL).
(.... scrittura dispense in corso ....)
!----------------------------------------------------------------------APPENDICE A - SIGLE E DEFINIZIONI UTILI
═══════════
Elenchiamo sinteticamente il significato di alcune sigle usate (glossari
piu' completi sono reperibili in rete, per esempio sul sito della Sun):
FNC (Federal Networking Council, sito www.fnc.gov):
Sistema globale di comunicazione basato sul protocollo TCP/IP
(acronimo di Transfer Control Protocol/Internet Protocol) e
successivi sviluppi futuri, che fornisce:
- indirizzamento logico univoco;
- comunicazione;
- accesso a servizi di alto livello basati sulla comunicazione.
WWW (World Wide Web): metodo ipertestuale e intuitivo per accedere alle
risorse su Internet, unendo al testo anche elementi grafici,
audio, video ed altre funzionalita' multimediali, comprese
applicazioni programmabili. Il tutto quindi suscettibile di
un'interfacciamento 'amichevole' (tramite grafica e mouse).
Quindi il Web e' grafico, inter-piattaforma, distribuito,
dinamico, multimediale, interattivo (web = ragnatela)
Server WEB: Computer gestore di servizi Internet memorizza le pagine WEB e le
invia al browser del Client
quando questo le richiede. Non e' pero' solo un file server
di rete, poiche' e' anche in grado, su richiesta del browser,
di eseguire dei programmi (script CGI).
Script: E' un testo, composto da una sequenza di comandi di scripting, che
viene eseguito da un interprete (scripting engine, come Perl,
JScript e VBScript)), producendo normalmente un output HTML da
inviare al browser come risultato dell'elaborazione (documento
dinamico). Possono essere facilmente prelevati da una pagina
HTML ed inseriti in un'altra con la tecnica 'copia&incolla'.
Script CGI (Common Gateway Interface): Sono programmi eseguibili dal server
WEB su richiesta del browser del computer client. In genere il
risultato dell'elaborazione viene inviato al client sotto forma
di pagina HTML. Un uso tipico e' quello di acquisire i dati
di registrazione di un cliente che sottoscrive un modulo per
accedere ad un servizio. L'elaborazione CGI comprendera'
l'inserimento dei dati del cliente nel data-base sul server,
la predisposizione di una pagina di risposta ed il suo invio al
computer client. Tutti i programmi CGI di uso piu' frequente
sono disponibili come componenti predefiniti di tutti i piu'
diffusi programmi editor HTML
Ipertesto: Documento composto di argomenti contenenti riferimenti ad altri
argomenti (collegamenti ipertestuali) al fine di consentirne la
lettura saltando da un argomento all'altro (navigazione).
Un esempio di utilizzo di ipertesti e' la Guida di Windows e
Hypercard di Macintosh.
Collegamento ipertestuale: e' un puntatore contenuto in una pagina WEB che
punta ad un altro file sul WEB che in genere e' un'altra pagina
WEB ma potrebbe anche essere un file multimediale o addirittura
un programma. La presenza di un collegamento ipertestuale e'
visibile in un testo con un colore diverso, mentre e' invisibile
su un'immagine (pero' il cursore cambia aspetto quando ci si passa
sopra). Cliccando su un collegamento ipertestuale il browser
preleva il file dall'indirizzo specificato e lo visualizza se e'
una pagina HTML oppure lo apre (con il programma associato: per
esempio con un riproduttore di suoni se e' un file WAV).
Linguaggio ipertestuale HTML (HyperText Markup Language): e' il linguaggio
per la definizione delle direttive per l'impaginazione e lo
sviluppo di documenti interattivi.
Il browser WEB esegue la formattazione della pagina in base a
queste direttive (tag) contenute nel codice HTML, adeguando la
larghezza delle righe alla larghezza dello schermo o della
finestra. Quindi browser diversi mostreranno visualizzazioni
diverse per la stessa pagina WEB. Tutti gli elementi della
pagina (informazioni e link) sono cosi' al loro posto ma
l'aspetto sul video potra' essere diverso. Specifiche curate
dal consorzio W3C (vedi http://www.w3.org).
HTML permette la creazione di pagine WEB interattive, nelle quali
possiamo incorporare veri programmi con JAVA, CGI, ActiveX e VRML
(Virtual Reality Modeling Language, per la visualizzazione di
scenari a tre dimensioni all'interno delle pagine WEB).
La codifica delle direttive (tag) necessarie al browser per
l'impaginazione, nel codice HTML non sono un compito semplice, ma
i nuovi editor HTML, progettati secondo la tecnica WYSIWYS ("What
You See Is What You Get") sollevano l'utente dall'obbligo di
conoscere i codici di formattazione del linguaggio ipertestuale,
lasciandolo concentrare piu' facilmente sul lavoro creativo.
Rete Internet: I computer collegati in Internet comunicano tra loro con il
protocollo TCP o UDP, secondo lo schema seguente:
Livello Applicazione: HTTP, FTP, telnet, ...
Livello Trasporto : TCP, UPD, ...
Livello
Rete
: IP, ...
Livello
Device
: Device driver, ...
L'utente programmera' in Java, per esempio, al livello
Applicazione usando le classi del package Java.net e potra'
scegliere TCP o UDP tra i protocolli di trasporto, in base
alle esigenze dell'applicazione.
HTTP (HyperText Transfer Protocol): protocollo a livello applicazione per
gestire sul server le risorse ipertestuali. Normalmente la
comunicazione HTTP usa una connessione TCP/IP (default port=80);
le specifiche pero' richiedono solo che il protocollo di
trasporto sia affidabile.
La comunicazione e' handshake: client e server si scambiano
messaggi contenenti anche 'meta-informazioni' in un formato
simile al MIME (usato per la posta elettronica multimediale).
TCP/IP: Il protocollo TCP/IP (Transfer Control Protocol/Internet Protocol)
e' alla base del software usato su Internet per la trasmissione
dei dati. E' costituito da 2 componenti: i protocolli IP e TCP.
IP : scompone i dati e li inserisce in pacchetti software in
modo che possano essere piu' facilmente trasferiti attraverso le reti. I computer 'router' lungo il percorso
istradano i pacchetti utilizzando gli indirizzi dei
computer sorgente e destinazione inseriti nei pacchetti,
fino a farli pervenire al computer di destinazione che,
quando li riceve, li riassembla.
TCP (Transfer Control Protocol) e' un protocollo basato sulla
connessione punto-punto dei due computer e garantisce il
flusso di dati, come e' richiesto da protocolli di applicazione, come HTTP o FTP o Telnet.
Il software del protocollo TCP assicura la correttezza del
riassemblaggio, chiedendo la ritrasmissione dei pacchetti
persi o danneggiati.
Quindi il protocollo TCP/IP permette la commutazione di pacchetto
(suddivisione dei dati in vari pacchetti e trasmissione commutata
dei pacchetti in modo da sfruttare al massimo la capacita' della
linea di trasmissione.
E' strutturato su 4 livelli:
- livello fisico (della rete);
- indirizzamento e trasmissione;
- controllo (con eventuale ritrasmissione) e gestione degli invii;
- livello applicazioni (genera i dati come richiesti per l'utente).
UPD:
Il protocollo UPD (User Datagram Protocol) e' invece un altro
protocollo di trasferimento di dati che non instaura una
connessione tra i due computers: uno trasmette pacchetti di
dati indipendenti dell'applicazione (datagrams) e non fa alcun
controllo sulla loro corretta ricezione: non viene cosi' garantita
ne' la ricezione ne' l'ordine di arrivo dei pacchetti, ma soltanto
il loro veloce invio.
UPD e' piu' veloce perche' elimina l'overhead temporale richiesto
per instaurare la connessione tra i due computer.
Un esempio del suo uso e' il 'ping', cioe' il test della qualita'
di una connessione: un diverso protocollo che assicurasse una
connessione affidabile renderebbe impossibile rilevare la qualita'
della linea.
Indirizzo IP: ciascun computer collegato ad Internet deve avere un indirizzo
IP univoco di 32 bit, che gli viene assegnato dal provider del
servizio di connettivita' Internet o dall'amministratore della
rete intranet, che a loro volta l'hanno ottenuto dall'organismo
internazionale a cio' preposto. Se si usa un account PPP/SLIP
l'indirizzo IP viene assegnato di volta in volta dal provider al
momento del collegamento.
Gli indirizzi IP dei computer sorgente e destinatario vengono
inseriti in ogni pacchetto e sono utilizzati dai computer router
per istradarli in maniera ottimale fino a farli giungere al
computer di destinazione.
L'indirizzo IP e' formato da quattro numeri (=0..255) di tre cifre
a cui corrisponde, in base al DNS (Domain Name System) il piu'
mnemonico e significativo indirizzo simbolico che usa l'utente
nella navigazione, secondo la struttura:
'protocollo.nomedominio.suffisso'
Esempio: l'indirizzo 199.170.0.150, corrispondente ad un server
dell'FBI, si trasforma in DNS nell'indirizzo www.fbi.gov (sito
ufficiale dell'FBI), molto piu' comodo da usare.
L'ultimo campo si chiama suffisso ed individua un dominio.
Oltre ai domini nazionali (es. IT=Italia, FR=Francia, ecc.) sono
attivi i seguenti altri:
EDU = Organizzazioni di ricerca e Universita';
COM = Organizzazioni commerciali;
GOV = Enti governativi;
MIL = Enti militari;
NET = Gestori di rete;
ORG = Altre organizzazioni.
Altri suffissi che saranno attivati sono: FIRM, STORE, WEB,
ARTS, REC, INFO, NOM.
Localizzatore URL (Uniform Resource Locator): e' lo standard di
indirizzamento delle risorse secondo il modello:
"protocollo.nomedominio.suffisso"
Il protocollo usato da internet e' HTTP.
Esempio:
"http://www.microsoft.com/index.html"
I browser Web sono in grado di usare anche altri protocolli
nell'indirizzo URL. Esempi:
1) per usare un protocollo FTP per scaricare files da un server
FTP l'indirizzo sara':
"ftp://nome_del_sito/percorso/nome_del_file"
Esempio: "ftp://ftp.netscape5.com/navigator/3.0/mac/README.TXT"
(se manca nome_file il server Web mostrera' l'elenco dei files
nella directory);
2) con il protocollo FILE si accede ad un file locale del computer.
Esempio: "file:///C|/WWW/INDEX.HTM"
Si noti che si usa | al posto dei due punti (usati nell'indicazione del numero della la porta, 80 pe default) e che si
usano sempre le barre / (slash anziche' backslash).
3) per accedere ad un server Gopher da un browser Web l'indirizzo
URL sara' del tipo: "gopher://nome_server_gopher/.
4) si puo' anche usare un protocollo di posta elettronica.
Esempio:
"mailto:[email protected]"
Si puo' cosi' inviare un messaggio all'indirizzo indicato.
Il localizzatore URL fornisce la localizzazione di un file sul
WEB e identifica il servizio Internet, come WWW o FTP, che
gestira' il file.
Nel caso di un protocollo http (significa che il file si trova
su un server WEB) il formato e' il seguente:
http://www.microsoft.com/prodotti/prodotto.htm#informazioni
Protocollo<--path di rete--> path <--NomeFile--> Segnalibro
Gli URL possono anche contenere l'indicazione del numero di porta,
che in pratica determina quale dei diversi processi attivi
sull'host dovra' gestire la richiesta, cioe' i protocolli di
trasporto TCP o UPD usano i numeri di porta per 'mappare' i dati
entranti nel server ad uno dei processi attivi sul server.
Esempio:
"http://www.microsoft.com:80/index.html"
(se mancante, http assume il numero di porta 80 come default)
Il numero di porta e' di 16 bit, quindi va da 0...65535, ma i
numeri 0...1023 sono riservati ai servizi del sistema.
Esempi di altri URL con protocolli diversi sono:
ftp://ftp.microsoft.com/italy/file.doc
(su un server FTP)
mailto:[email protected]
(il browser apre il modulo di E.mail)
file://computer.host/file.doc (il file.doc sta su computer.host)
Se l'URL e' completo si dice assoluto, altrimenti e' relativo (alla
pagina corrente). Cioe' se computer o directory non sono indicati
vengono usati quelli del file corrente, mentre se il file non e'
indicato viene assunto come predefinito index.htm
Se il segnalibro esiste il browser visualizza la pagina a partire
dalla posizione del segnalibro.
Intranet: e' una rete basata sulla tecnologia Internet, ma sviluppata per
uso privato; realizza un Web interno, cioe' riservato ai membri
di una stessa organizzazione.
Pur essendo basata sulla tecnologia Internet, che permette la
connettivita' di utenti che possono essere migliaia e sparsi
anche in localita' molto distanti, una rete intranet mantiene le
caratteristiche di una rete privata, poiche' viene realizzata
all'interno di un 'firewall', cioe' di un meccanismo software
capace di bloccare eventuali tentativi di accesso non autorizzati
dall'esterno, garantendo allo stesso tempo l'accesso all'intera
rete intranet da parte degli utenti ad essa connessi.
All'interno della rete intranet l'amministratore puo' concedere
particolari diritti agli utenti connessi, controllando con
certificati e firme digitali le sicurezze dei browser (vedasi
capitolo relativo).
I vantaggi delle reti intranet derivano dalla possibilita' di
usare tanti strumenti disponibili commercialmente con i quali si
puo' facilmente:
- Distribuire documenti in formato elettronico
- Gestire i documenti ed i dati per il lavoro dell'organizzazione
- Fornire accesso al data-base comune
- Distribuire ed aggiornare programmi
- Distribuire elaborazioni e input/output
- Realizzare forum di discussione o collegamenti diretti audio/
video.
Extranet: e' una rete Intranet estesa ad alcuni membri esterni alla
organizzazione, ma interessati ad accedere all'intranet
aziendale (come clienti e fornitori, partner d'affari, ecc.).
L'accesso viene controllato dal server aziendale tramite
username, password e firme digitali.
Servizi messi a disposizione da Internet:
- Posta Elettronica (E-Mail), con messaggi comprendenti audio, video e
immagini
- World Wide Web (enorme serbatoio di informazioni, organizzato come un
insieme di siti tra cui e' possibile 'navigare' (to browse) con i
collegamenti ipertestuali; con un Bookmark si puo' memorizzare un utile
indirizzo Web per poi tornarci facilmente);
- Bullettin Board (newsgroup e forum) con cui si realizzano gruppi di
discussione scrivendo messaggi su un 'server news' che possono essere
letti da un client dotato del software 'newsreader'.
- comunicazione diretta (es. canali IRC=Internet Relay Chat e videoconferenze con connessione diretta video/voce, senza costi di
collegamenti interurbani).
- FTP (File Transfer Protocol) usato per il trasferimento di file.
- Gopher per l'esplorazione di Internet con una serie di menu'
- i servizi avanzati.
Gli strumenti 'intelligenti' sono:
- i browser, come Netscape Navigator o Microsoft Internet Explorer
(IE 4.0), prelevano dal server Web indicato nell'indirizzo internet
(con il protocollo indicato) le informazioni e le formattano per
visualizzarle sul proprio sistema, in base alle sue caratteristiche
ed alle funzionalita' attivate;
- i motori di ricerca, come Altavista (www.altavista.digital.com) o
HotBot (www.hotbot.com), che gestiscono indici ricercando i link su
un dato tema;
- le mailing list;
- i newsgroup (che sono bacheche pubbliche di comunicazione via E-mail);
- la Usenet (un insieme di newsgroup, basato su computer "news server"
che si sincronizzano continuamente in modo da tenere tutte le news
aggiornate;
- downloading o trasferimento di files tra due computer con il protocollo
FTP (File Transfer Protocol).
Attivita' specifiche per Internet:
Editoria, Pubblicita', Commercio elettronico, Applicazioni avanzate (Java,
Realta' virtuale,...), Telelavoro, ecc.
ALTRE INFORMAZIONI UTILI
========================
Elenco di sigle e parole usate (consultare il glossario per le altre):
-----------------------------WYSIWYS = tipo di visualizzazione usato da editor HTML come Front Page
(WYSIWYS="What You See Is What You Get")
Provider = Societa' che fornisce accesso alla rete tramite uno o piu' POP
(Point Of Presence), cioe' numeri telefonici.
POP,POP3 = Post Office Protocol (l'ultima versione e' la terza POP3, piu'
usata)
IMAP = Internet Message Access Protocol (concorrente di POP3, piu' evoluto
ma meno diffuso)
SNMP = Simply Network Management Protocol ( e' usato dal programma
'Agente SNMP' caricato nei computer client che vogliono monitorare
e/o amministrare l'attivita' di rete)
Altre sigle:
MSDN = logo for MicroSoft Developers Network
JDK = Java Development Kit
IDE = Integrated Development Environment
RAD = Rapid Application Development
API = Application Programming Interfaces
SQL = Structured Query Language
ODBC = Open Database Connectivity (driver per compatib.esterna di database)
GIF = Graphics Interchange Format
JPEG = Join Photographics Experts Group
PNG = Portable Network Graphics
W3C = World Wide Web Consortium
Funzioni disponibili su Internet:
--------------------------------- Navigazione
- E-mail
- Newsgroup e Forum
- Download di files
- Teleconferenza/Videoconferenza
- Chat
- Multiutenza
- Editing HTML
- Pubblicazione on-line di siti
- Integrazione di software esterni
- Supporto di plug-in
Programmi disponibili in Windows 98:
----------------------------------Internet Explorer: browser con navigazione a menu' o a barra di pulsanti;
OutLook Express: per E-mail e per consultazione di newsgroup (come Eudora);
FrontPage Express: come editor HTML;
Microsoft Chat: per il chat on-line su Internet con immagini e suoni;
NetMeeting: chat con supporto per videoconferenze;
Wizard di connessione: per creare facilmente gli accessi ad Internet;
NetShow Player: per presentazioni multimediali on-line.
HyperTerminal: programma per collegarsi ad un computer remoto o ad un
BBS (Bullettin Board Service); basta seguire le istruzioni
su video per usufruire del servizio;
Motori di ricerca ed esempi di siti Web:
---------------------------------------AltaVista: www.altavista.com
HotBot:
www.hotbot.com
NewsBot:
www.newsbot.com (versione di HotBot dedicata al mondo UseNet)
Virgilio: www.virgilio.it (in italiano)
Software:
WinFiles:
VolFTP:
Eudora:
Tucows:
www.winfiles.com (serbatoio di software di tutti i tipi)
www.volftp.it
www.eudora.com
www.tucows.com (raccolta di shareware, plug-in per browser, ecc.)
Turismo:
Amadeus: www.amadeus.net (network internazionale per prenotazioni, ecc.)
Canale Turismo Tin: http://turismo.tin.it/ (informazioni sul turismo)
WeatherLab: www.weatherlab.com (servizio di previsioni meteo)
Cultura:
Alice: www.alice.it
Amazon: www.amazon.com (libreria virtuale con catalogo di ricerca)
Rock On Line: www.rockol.it (informazioni su eventi musicali, ecc.)
Mondo Media: www.tin.it/mondomedia
Mailing List:
www.cilea.it/maillist
www.cilea.it/WWW-map/
www.paginegialle.it
http://mailory.tin.it/
National Geographic: www.nationalgeographic.com
Aiuto per nuovi utenti:
news.announce.newusers
news.newusers.questions
(nome del newsgroup)
Demo di applicazioni ingegneria:
www.leader.it
(internet/intranet)
Corso minimo: www.freesoft.org/CIE/index.htm
!----------------------------------------------------------------------APPENDICE B - Il simulatore H6809
═══════════
Uno dei campi di applicazione dei computer piu' di successo e' quello
delle simulazioni. Il successo deriva dal fatto che, una volta simulato
in processo o un apparato, risulta molto agevole, economico e veloce
verificarne il comportamento in funzione dei parametri costruttivi e
quindi ottimizzarli prima della sua onerosa costruzione effettiva.
I fisici sono soliti simulare al computer gli apparati sperimentali di
rivelazione dei fenomeni fisici prima della loro costruzione, assumendo
accettabili modelli matematici come descrizione del loro funzionamento,
anche in quei casi in cui l'indagine fisica li portera' ad investigare
su fenomeni fino ad allora inesplorati: esempi tipici sono i programmi
'Montecarlo', di cui viene fatto un semplice esempio nelle esercitazioni
(simulazione Montecarlo dello 'scattering coulombiano').
Argomento centrale delle esercitazioni pratiche e' invece la simulazione
del funzionamento di un processore Motorola 6809 (semplificato) fatta
con un programma Pascal su PC-IBM. Oltre a comprendere il funzionamento
di un tale simulatore, lo studente potra' usarlo per eseguire programmi
in codice M6809 senza avere fisicamente disponibile questo processore.
Una tale metodologia e' chiaramente di grande utilita' nei casi di
progettazione di nuove macchine elettroniche, consentendone il test
prima della costruzione.
Il listato sorgente del simulatore e' fornito sul dischetto delle
esercitazioni con due errori che ne alterano, sia pur di poco, il
funzionamento. Viene richiesto allo studente di rivelare questi errori,
conoscendo il corretto funzionamento del processore M6809, e quindi
di rimuoverli.
Il simulatore potra' poi essere usato per le esercitazioni sui
programmi scritti in linguaggio a basso livello (Assembly e linguaggio
macchina) per il processore H6809.
!----------------------------------------------------------------------APPENDICE C - Programma delle esercitazioni
═══════════
PROGRAMMA DI LAVORO DURANTE LE ESERCITAZIONI PRATICHE:
-----------------------------------------------------1) Uso dei comandi elementari del Sistema Operativo MS-DOS
2) Uso dell'Editor del TURBOPASCAL
3) Prove di uso delle istruzioni Pascal in semplici programmi ( xxxDEMO.PAS )
4) Comprensione ed ampliamento del programma ADDING.PAS
5) Studio del programma Monitor
6) Studio del programma di simulazione H6809BUG.PAS (con BINPROG.PAS);
ricerca ed eliminazione degli errori ivi contenuti
7) Studio del microcomputer H6809 simulato su IBM-PC, scrivendo ed eseguendo
un semplice programma in linguaggio macchina
8) Ampliamento del simulatore H6809 introducendovi altre istruzioni come
quelle di branch condizionato o di I/O o il sistema d'interruzione
9) Realizzazione in Basic di un simulatore dello scattering coulombiano
con il metodo di Montecarlo
10) Programmazione concorrente del Montecarlo su una LAN in elaborazione
parallela ('farm' di computer).
11) Uso dell'Editor dell'ambiente JDK1.3 (Java Developmenti Kit)
12) Prove di uso delle istruzioni Java in semplici programmi (xxxdemo.java):
PrimoEsempio, SecondoEsempio, TerzoEsempio, Test0, Root, NewRoot,
SwapTest, SwapTest2, Riordina, VirusLook
QuoteLotto: esempio con input da tastiera e chiamata a metodo
EmployeeTest,
H6809h: Monitor H6809 scritto in java
Root, EsempioApplet: esempio di applet
Prova: programma contenente un errore da trovare
13) Studio del programma Monitor H6809g.java, con particolare attenzione
all'uso dell' oggetto Byte (esempio di programmazione ad oggetti)
14) Uso del server httpServer per connessione HTTP con un browser.
AVVERTENZA IMPORTANTE
=====================
Le esercitazioni si svolgono usando un dischetto personale
per ogni studente: su questo dischetto vi sono i files
contenenti le dispense del corso, gli appunti (LEZ??.PAS) ed
i programmi per le esercitazioni.
Gli esercizi e le dispense su Internet, sulla programmazione ad
oggetti e sul linguaggio Java sono consegnati agli studenti
all'inizio del modulo B (subito dopo Pasqua).
Lo studente dovr? riconsegnare questo dischetto al docente al
termine delle esercitazioni e non portare dischetti propri per
ragioni di sicurezza e protezione dai 'virus'. Un virus e' un
programma nascosto all'interno di un altro programma usato
dell'utente. Quando viene lanciato in esecuzione esso modifica
gli altri programmi eseguibili presenti sul dischetto e nel
computer, installandosi in maniera invisibile nella memoria e
nel sistema operativo, in modo da rimanere stabilmente installato
nella macchina. Questa risulta così 'infettata' ed in grado di
infettare tutti i programmi eseguibili, presenti sui dischetti
in essa inseriti da utenti ignari . Questo potenziale processo
di contagio dei dischetti del nostro corso e' possibile sia nei
computers del nostro laboratorio che in quelli del CATTID,
poiche' sono centri aperti a tutti e qualcuno puo' portare
dischetti infetti dall'esterno.
I vostri dischetti, una volta infettati, se portati fuori dall'Universita' possono infettare il vostro computer di casa,
dell'ufficio, ecc.
Per questi motivi lo studente deve riconsegnare il suo dischetto al docente al termine delle esercitazioni e non portare mai
dischetti propri al laboratorio o al CATTID.
!----------------------------------------------------------------------Argomenti
--------GUI
EVENTI
(SICUREZZA)
Data
---9/5
"
no
APPLET
RETI
11/5
"
LAB. (Java)
INTER-RETI
INDIRIZZAMENTO IP
PROTOCOLLO TCP
16/5
"
"
M
18/5
"
"
V
INTERNET
HTML
CGI
LAB. (seminario)
Acquisiz.dati+CAMAC
VME + FASTBUS
LAB. (HTML+CGI)
(ARCHITETT.PARALLELE)
M
V
14/5
L
21/5
23/5
25/5
L
M
V
28/5
30/5
L
M