Skip to content

8. Allegati

8.1. Gli strumenti per lo sviluppo web

Qui indichiamo dove trovare e come installare gli strumenti necessari per lo sviluppo web. Alcune versioni degli strumenti sono state aggiornate ed è possibile che le spiegazioni fornite qui non siano più valide per le versioni più recenti. Il lettore dovrà quindi adattarsi... Nel corso di programmazione web utilizzeremo essenzialmente i seguenti strumenti, tutti disponibili gratuitamente:

  • un browser recente in grado di visualizzare XML. Gli esempi del corso sono stati testati con Internet Explorer 6.
  • un JDK (Java Development Kit) recente. Gli esempi del corso sono stati testati con il JDK 1.4. Questo JDK include il plug-in Java 1.4 per i browser, che consente a questi ultimi di visualizzare applet Java che utilizzano Java 1.4.
  • Un ambiente di sviluppo Java per scrivere servlet Java. In questo caso si tratta di JBuilder 7.
  • server web: Apache, PWS (Personal Web Server), Tomcat.
    • Apache verrà utilizzato per lo sviluppo di applicazioni web in PERL (Practical Extracting and Reporting Language) o PHP (Personal Home Page)
    • PWS sarà utilizzato per lo sviluppo di applicazioni web in ASP (Active Server Pages) o PHP
    • Tomcat sarà utilizzato per lo sviluppo di applicazioni web tramite servlet Java o pagine JSP (Java Server Pages)
  • un'applicazione di gestione di database: MySQL
  • EasyPHP: uno strumento che integra il server web Apache, il linguaggio PHP e il SGBD MySQL

8.1.1. Server Web, browser, linguaggi di scripting

  1. Principali server Web
    • Apache (Linux, Windows)
    • Internet Information Server IIS (NT), Personal Web Server PWS (Windows 9x)
  1. Principali browser
    • Internet Explorer (Windows)
    • Netscape (Linux, Windows)
  1. Linguaggi di scripting lato server
    • VBScript (IIS, PWS)
    • JavaScript (IIS, PWS)
    • Perl (Apache, IIS, PWS)
    • PHP (Apache, IIS, PWS)
    • Java (Apache, Tomcat)
    • Linguaggi .NET
  1. Linguaggi di scripting lato browser
    • VBScript (IE)
    • JavaScript (IE, Netscape)
    • PerlScript (IE)
    • Java (IE, Netscape)

8.1.2. Dove trovare gli strumenti

Netscape
http://www.netscape.com/ (link ai download)
Internet Explorer
http://www.microsoft.com/windows/ie/default.asp
PHP
http://www.php.net
http://www.php.net/downloads.php (file binari per Windows)
PERL
http://www.activestate.com http://www.activestate.com/Products/
http://www.activestate.com/Products/ActivePerl/
Vbscript, Javascript
http://msdn.microsoft.com/scripting (seguire il link allo script di Windows)
JAVA
http://java.sun.com/
http://java.sun.com/downloads.html (JSE)
http://java.sun.com/j2se/1.4/download.html
Apache
http://www.apache.org/
http://www.apache.org/dist/httpd/binaries/win32/
PWS
incluso nel pacchetto di opzioni NT 4.0 per Windows 95
incluso nel CD per Windows 98
http://www.microsoft.com/ntserver/nts/downloads/recommended/NT4OptPk/win95.asp
IIS 
(windows NT/2000)
http://www.microsoft.com
Tomcat
http://jakarta.apache.org/tomcat/
JBuilder
http://www.borland.com/jbuilder/
http://www.borland.com/products/downloads/download_jbuilder.html
EasyPHP
http://www.easyphp.org/
http://www.easyphp.org/telechargements.php3

8.1.3. EasyPHP

Questa applicazione è molto pratica in quanto riunisce in un unico pacchetto:

  • il server Web Apache (1.3.x)
  • il linguaggio PHP (4.x)
  • il SGBD MySQL (3.23.x)
  • uno strumento di amministrazione di MySQL: PhpMyAdmin

L'applicazione di installazione si presenta come segue:

Image

L'installazione di EasyPHP non presenta problemi e nel sistema di file viene creata una struttura ad albero:

Image

easyphp.exe
l'eseguibile dell'applicazione
apache
la struttura di directory del server Apache
mysql
la struttura di directory di MySQL SGBD
phpmyadmin
la struttura dell'applicazione phpMyAdmin
php
la struttura di php
www
radice della struttura delle pagine web fornite dal server Apache di EasyPHP
cgi-bin
struttura in cui è possibile inserire gli script CGI per il server Apache

Il vantaggio principale di EasyPHP è che l'applicazione viene fornita preconfigurata. Pertanto, Apache, PHP e MySQL sono già configurati per funzionare insieme. Quando si avvia EasyPhp tramite il collegamento nel menu dei programmi, viene visualizzata un'icona in basso a destra dello schermo.

È la «E» con un punto rosso che deve lampeggiare se il server web Apache e il database MySQL sono operativi. Cliccandoci sopra con il tasto destro del mouse, si accede alle opzioni del menu:

Image

L'opzione Administration consente di effettuare impostazioni e test di funzionamento:

Image

8.1.3.1. Amministrazione PHP

Il pulsante «Informazioni su PHP» dovrebbe consentire di verificare il corretto funzionamento della coppia Apache-PHP: dovrebbe apparire una pagina informativa PHP:

Image

Il pulsante «Estensioni» mostra l’elenco delle estensioni installate per PHP. Si tratta, in realtà, di librerie di funzioni.

Image

La schermata sopra mostra, ad esempio, che le funzioni necessarie per l’utilizzo del database MySQL sono effettivamente presenti.

Il pulsante «Impostazioni» mostra le credenziali dell’amministratore del database login/motdepasse.

Image

L'utilizzo del database MySQL va oltre lo scopo di questa breve presentazione, ma è chiaro che sarebbe necessario impostare una password per l'amministratore del database.

8.1.3.2. Amministrazione di Apache

Sempre nella pagina di amministrazione di EasyPHP, il link «vos alias» consente di definire alias associati a una directory. Ciò permette di collocare le pagine web in una posizione diversa dalla directory www della struttura di easyPhp.

Image

Se nella pagina sopra indicata si inseriscono le seguenti informazioni:

Image

e si utilizza il pulsante valider, al file <easyphp>\apache\conf\httpd.conf vengono aggiunte le seguenti righe:

    Alias /st/ "e:/data/serge/web/"

    <Directory "e:/data/serge/web">
        Options FollowSymLinks Indexes
        AllowOverride None
        Order deny,allow
        allow from 127.0.0.1
        deny from all
    </Directory>

<easyphp> indica la directory di installazione di EasyPHP. httpd.conf è il file di configurazione del server Apache. È quindi possibile ottenere lo stesso risultato modificando direttamente questo file. Una modifica al file httpd.conf viene normalmente applicata immediatamente da Apache. Se ciò non dovesse avvenire, sarebbe necessario arrestarlo e riavviarlo, sempre tramite l’icona di EasyPHP:

Image

Per concludere il nostro esempio, ora è possibile inserire delle pagine web nella struttura di directory e:\data\serge\web:

C:\winnt\system32>dir e:\data\serge\web\html\balises.htm

14/07/2002  17:02                3 767 balises.htm

e richiamare questa pagina utilizzando l'alias st:

Image

In questo esempio, il server Apache è stato configurato per funzionare sulla porta 81. La sua porta predefinita è 80. Questo aspetto è controllato dalla seguente riga del file httpd.conf già visto in precedenza:

Port 81

8.1.3.3. Il file di configurazione di Apache htpd.conf

Quando si desidera configurare Apache in modo più dettagliato, è necessario modificare “manualmente” il suo file di configurazione httpd.conf, che si trova qui nella cartella <easyphp>\apache\conf:

Image

Ecco alcuni punti da tenere a mente riguardo a questo file di configurazione:

ligne(s)
ruolo
ServerRoot "D:/Program Files/Apache Group/Apache"
indica la cartella in cui si trova la struttura di Apache
Port 80
indica su quale porta opererà il server Web. Di norma è la 80. Modificando questa riga, è possibile far funzionare il server Web su un'altra porta
ServerAdmin root@istia.univ-angers.fr
l'indirizzo e-mail dell'amministratore del server Apache
ServerName stahe.istia.uang
il nome del computer su cui "gira" il server Apache
ServerRoot "E:/Program Files/EasyPHP/apache"
la directory di installazione del server Apache. Quando nel file di configurazione compaiono nomi di file relativi, questi sono relativi a questa cartella.
DocumentRoot "E:/Program Files/EasyPHP/www"
la cartella radice della struttura delle pagine Web fornite dal server. In questo caso, l'URL http://machine/rep1/fic1.html corrisponderà al file E:\Program Files\EasyPHP\www\rep1\fic1.html
<Directory "E:/Program Files/EasyPHP/www">
imposta le proprietà della cartella precedente
ErrorLog logs/error.log
cartella dei log, quindi in realtà <ServerRoot>\logs\error.log: E:\Program Files\EasyPHP\apache\logs\error.log. Questo è il file da controllare se notate che il server Apache non funziona.
    ScriptAlias /cgi-bin/ "E:/Program Files/EasyPHP/cgi-bin/"
E:\Program Files\EasyPHP\cgi-bin sarà la radice della struttura in cui sarà possibile inserire gli script CGI. Pertanto, l'URL dello script CGI sarà: http://machine/cgi-bin/rep1/script1.pl E:\Program Files\EasyPHP\cgi-bin\rep1\script1.pl.
<Directory "E:/Program Files/EasyPHP/cgi-bin/">
imposta le proprietà della cartella sopra indicata
LoadModule php4_module "E:/Program
 Files/EasyPHP/php/php4apache.dll"
AddModule mod_php4.c
righe di caricamento dei moduli che consentono ad Apache di funzionare con PHP4.
    AddType application/x-httpd-php
 .phtml .pwml .php3 
.php4 .php .php2 .inc
definisce i suffissi dei file da considerare come file da elaborare da parte di PHP

8.1.3.4. Amministrazione di MySQL con PhpMyAdmin

Nella pagina di amministrazione di EasyPhp, fare clic sul pulsante PhpMyAdmin:

Image

Il menu a tendina sotto Accueil consente di visualizzare i database
dati attuali.
Il numero tra parentesi indica il numero di tabelle. Se si
sceglie un database, vengono visualizzate le tabelle in esso contenute:

La pagina web offre una serie di operazioni sul database:

Image

Se si clicca sul link Afficher da user:

Image

Qui c'è un solo utente: root, che è l'amministratore di MySQL. Seguendo il link Modifier, si potrebbe modificare la sua password, che al momento è vuota, cosa sconsigliata per un amministratore.

Non ci soffermeremo ulteriormente su PhpMyAdmin, che è un software ricco di funzionalità e che meriterebbe una descrizione di diverse pagine.

8.1.4. PHP

Abbiamo visto come ottenere PHP tramite l’applicazione EasyPhp. Per ottenere direttamente PHP, si acceda al sito http://www.php.net.

PHP non è utilizzabile solo in ambito web. È possibile utilizzarlo come linguaggio di scripting su Windows. Creare il seguente script e salvarlo con il nome date.php:

<?
   // script PHP che visualizza l'ora
  $maintenant=date("j/m/y, H:i:s",time());
  echo "Nous sommes le $maintenant";
?>

In una finestra DOS, selezionate la directory di date.php ed eseguite il programma:

E:\data\serge\php\essais>"e:\program files\easyphp\php\php.exe" date.php
X-Powered-By: PHP/4.2.0
Content-type: text/html

Nous sommes le 18/07/02, 09:31:01

8.1.5. PERL

È preferibile che Internet Explorer sia già installato. Se è presente, Active Perl lo configurerà in modo che accetti gli script PERL nelle pagine HTML, script che saranno eseguiti dallo stesso IE sul lato client. Il sito di Active Perl si trova all'indirizzo URL http://www.activestate.comA l'installazione, PERL verrà installato in una directory che chiameremo <perl>. Contiene la seguente struttura:

DEISL1   ISU        32 403  23/06/00  17:16 DeIsL1.isu
BIN            <REP>        23/06/00  17:15 bin
LIB            <REP>        23/06/00  17:15 lib
HTML           <REP>        23/06/00  17:15 html
EG             <REP>        23/06/00  17:15 eg
SITE           <REP>        23/06/00  17:15 site
HTMLHELP       <REP>        28/06/00  18:37 htmlhelp

Il file eseguibile perl.exe si trova in <perl>\bin. Perl è un linguaggio di scripting che funziona su Windows e Unix. Viene inoltre utilizzato nella programmazione di WEB. Scriviamo un primo script:

# script PERL che visualizza l'ora

# moduli
use strict;

# programma
my ($secondes,$minutes,$heure)=localtime(time);
print "Il est $heure:$minutes:$secondes\n";

Salvate questo script in un file denominato heure.pl. Aprite una finestra DOS, posizionatevi nella directory dello script precedente ed eseguite lo script:

E:\data\serge\Perl\Essais>e:\perl\bin\perl.exe heure.pl
Il est 9:34:21

8.1.6. Vbscript, Javascript, Perlscript

Questi linguaggi sono linguaggi di scripting per Windows. Possono funzionare in diversi contesti, come ad esempio

  • Windows Scripting Host per un utilizzo diretto in Windows, in particolare per scrivere script di amministrazione di sistema
  • Internet Explorer. Viene quindi utilizzato all’interno delle pagine HTML, alle quali conferisce una certa interattività impossibile da ottenere con il solo linguaggio HTML.
  • Internet Information Server (IIS), il server Web di Microsoft su NT/2000, e il suo equivalente Personal Web Server (PWS) su Win9x. In questo caso, VBScript viene utilizzato per la programmazione lato server web, una tecnologia denominata ASP (Active Server Pages) da Microsoft.

Si scarica il file di installazione da URL: http://msdn.microsoft.com/scripting e si seguono i link relativi a Windows Script. Vengono installati:

  • il contenitore Windows Scripting Host, che consente l’utilizzo di vari linguaggi di scripting, quali VBScript e JavaScript, ma anche altri come PerlScript, fornito con Active Perl.
  • un interprete VBscript
  • un interprete JavaScript

Vediamo alcuni test rapidi. Creiamo il seguente programma vbscript:

' una classe
class personne
  Dim nom
  Dim age
End class

' creazione di un oggetto persona
Set p1=new personne
With p1
  .nom="dupont"
  .age=18
End With

' visualizzazione delle proprietà della persona p1
With p1
  wscript.echo "nom=" & .nom
  wscript.echo "age=" & .age
End With

Questo programma utilizza oggetti. Chiamiamolo objets.vbs (il suffisso vbs indica un file VBScript). Accediamo alla cartella in cui si trova ed eseguiamolo:

E:\data\serge\windowsScripting\vbscript\poly\objets>cscript objets.vbs
Microsoft (R) Windows Script Host Version 5.6
Copyright (C) Microsoft Corporation 1996-2001. All rights reserved.

nom=dupont
age=18

Ora creiamo il seguente programma JavaScript che utilizza gli array:

// array in una variante
// array vuoto
tableau=new Array();
affiche(tableau);
// array che cresce dinamicamente
for(i=0;i<3;i++){
  tableau.push(i*10);
}
// visualizzazione tabella
affiche(tableau);
// ancora
for(i=3;i<6;i++){
  tableau.push(i*10);
}
affiche(tableau);

// tabelle multidimensionali
WScript.echo("-----------------------------");

tableau2=new Array();
for(i=0;i<3;i++){
  tableau2.push(new Array());
  for(j=0;j<4;j++){
    tableau2[i].push(i*10+j);
  }//for j
}// for i
affiche2(tableau2);

// fine
WScript.quit(0);

// ---------------------------------------------------------
function affiche(tableau){
  // visualizzazione tabella
  for(i=0;i<tableau.length;i++){
    WScript.echo("tableau[" + i + "]=" + tableau[i]);
  }//per
}//funzione

// ---------------------------------------------------------
function affiche2(tableau){
   // visualizzazione tabella
  for(i=0;i<tableau.length;i++){
    for(j=0;j<tableau[i].length;j++){
      WScript.echo("tableau[" + i + "," + j + "]=" + tableau[i][j]);
    }// per j
  }//per i
}//funzione

Questo programma utilizza array. Chiamiamolo tableaux.js (il suffisso js indica un file JavaScript). Accediamo alla directory in cui si trova ed eseguiamolo:

E:\data\serge\windowsScripting\javascript\poly\tableaux>cscript tableaux.js
Microsoft (R) Windows Script Host Version 5.6
Copyright (C) Microsoft Corporation 1996-2001. Tous droits réservés.

tableau[0]=0
tableau[1]=10
tableau[2]=20
tableau[0]=0
tableau[1]=10
tableau[2]=20
tableau[3]=30
tableau[4]=40
tableau[5]=50
-----------------------------
tableau[0,0]=0
tableau[0,1]=1
tableau[0,2]=2
tableau[0,3]=3
tableau[1,0]=10
tableau[1,1]=11
tableau[1,2]=12
tableau[1,3]=13
tableau[2,0]=20
tableau[2,1]=21
tableau[2,2]=22
tableau[2,3]=23

Un ultimo esempio in Perlscript per concludere. Per poter utilizzare Perlscript è necessario avere installato Active Perl.

<job id="PERL1">
  <script language="PerlScript">
       # del Perl classico
    %dico=("maurice"=>"juliette","philippe"=>"marianne");
    @cles= keys %dico;
    for ($i=0;$i<=$#chiavi;$i++){
        $cle=$cles[$i];
      $valeur=$dico{$cle};
        $WScript->echo ("clé=".$cle.", valeur=".$valeur);
    }
     # di PerlScript che utilizza gli oggetti Windows Script
    $dico=$WScript->CreateObject("Scripting.Dictionary");
    $dico->add("maurice","juliette");
    $dico->add("philippe","marianne");
    $WScript->echo($dico->item("maurice"));
    $WScript->echo($dico->item("philippe"));    
  </script>
</job>

Questo programma illustra la creazione e l'utilizzo di due dizionari: uno nel classico stile Perl, l'altro con l'oggetto Scripting Dictionary di Windows Script. Salviamo questo codice nel file dico.wsf (wsf è l'estensione dei file Windows Script). Accediamo alla cartella contenente questo programma ed eseguiamolo:

E:\data\serge\windowsScripting\perlscript\essais>cscript dico.wsf
Microsoft (R) Windows Script Host Version 5.6
Copyright (C) Microsoft Corporation 1996-2001. Tous droits réservés.

clé=philippe, valeur=marianne
clé=maurice, valeur=juliette
juliette
marianne

Perlscript può utilizzare gli oggetti del contenitore in cui viene eseguito. In questo caso si trattava di oggetti del contenitore Windows Script. Nel contesto della programmazione web, gli script VBscript, JavaScript e Perlscript possono essere eseguiti sia all’interno del browser IE, sia all’interno di un server PWS o IIS. Se lo script è piuttosto complesso, può essere opportuno testarlo al di fuori del contesto web, all’interno del contenitore Windows Script come visto in precedenza. In questo modo sarà possibile testare solo le funzioni dello script che non utilizzano oggetti specifici del browser o del server. Anche con questa limitazione, questa possibilità rimane interessante poiché in genere è piuttosto scomodo eseguire il debug di script in esecuzione all’interno di server web o browser.

8.1.7. JAVA

Java è disponibile all’indirizzo URL: http://www.sun.com e si installa in una struttura di directory che chiameremo <java>, contenente i seguenti elementi:

22/05/2002  05:51       <DIR>          .
22/05/2002  05:51       <DIR>          ..
22/05/2002  05:51       <DIR>          bin
22/05/2002  05:51       <DIR>          jre
07/02/2002  12:52                8 277 README.txt
07/02/2002  12:52               13 853 LICENSE
07/02/2002  12:52                4 516 COPYRIGHT
07/02/2002  12:52               15 290 readme.html
22/05/2002  05:51       <DIR>          lib
22/05/2002  05:51       <DIR>          include
22/05/2002  05:51       <DIR>          demo
07/02/2002  12:52           10 377 848 src.zip
11/02/2002  12:55       <DIR>          docs

Nella cartella bin si trovano javac.exe, il compilatore Java, e java.exe, la macchina virtuale Java. È possibile eseguire i seguenti test:

  1. Scrivere il seguente script:
//programma Java che visualizza l'ora

import java.io.*;
import java.util.*;

public class heure{
  public static void main(String arg[]){
     // si recuperano data e ora
     Date maintenant=new Date();
      // visualizzazione
     System.out.println("Il est "+maintenant.getHours()+
        ":"+maintenant.getMinutes()+":"+maintenant.getSeconds());
  }//main
}//classe
  1. Salvare questo programma con il nome heure.java. Aprire una finestra DOS. Passare alla directory del file heure.java e compilarlo:
D:\data\java\essais>c:\jdk1.3\bin\javac heure.java
Note: heure.java uses or overrides a deprecated API.
Note: Recompile with -deprecation for details.

Nel comando sopra riportato, c:\jdk1.3\bin\javac deve essere sostituito dal percorso esatto del compilatore javac.exe. Nella stessa directory di heure.java deve essere presente un file heure.class, che è il programma che verrà ora eseguito dalla macchina virtuale java.exe.

  1. Eseguire il programma:
D:\data\java\essais>c:\jdk1.3\bin\java heure
Il est 10:44:2

8.1.8. Server Apache

Abbiamo visto che è possibile ottenere il server Apache tramite l'applicazione EasyPhp. Per scaricarlo direttamente, andremo sul sito di Apache: http://www.apache.org. L'installazione crea una struttura di directory in cui si trovano tutti i file necessari al funzionamento del server. Chiamiamo questa directory <apache>. Essa contiene una struttura simile alla seguente:

UNINST   ISU       118 805  23/06/00  17:09 Uninst.isu
HTDOCS         <REP>        23/06/00  17:09 htdocs
APACHE~1 DLL       299 008  25/02/00  21:11 ApacheCore.dll
ANNOUN~1             3 000  23/02/00  16:51 Announcement
ABOUT_~1            13 197  31/03/99  18:42 ABOUT_APACHE
APACHE   EXE        20 480  25/02/00  21:04 Apache.exe
KEYS                36 437  20/08/99  11:57 KEYS
LICENSE              2 907  01/01/99  13:04 LICENSE
MAKEFI~1 TMP        27 370  11/01/00  13:47 Makefile.tmpl
README               2 109  01/04/98   6:59 README
README   NT          3 223  19/03/99   9:55 README.NT
WARNIN~1 TXT           339  21/09/98  13:09 WARNING-NT.TXT
BIN            <REP>        23/06/00  17:09 bin
MODULES        <REP>        23/06/00  17:09 modules
ICONS          <REP>        23/06/00  17:09 icons
LOGS           <REP>        23/06/00  17:09 logs
CONF           <REP>        23/06/00  17:09 conf
CGI-BIN        <REP>        23/06/00  17:09 cgi-bin
PROXY          <REP>        23/06/00  17:09 proxy
INSTALL  LOG         3 779  23/06/00  17:09 install.log
conf
cartella dei file di configurazione di Apache
logs
cartella dei file di log (monitoraggio) di Apache
bin
i file eseguibili di Apache

8.1.8.1. Configuration

Nella cartella <Apache>\conf si trovano i seguenti file: httpd.conf, srm.conf, access.conf. Nelle ultime versioni di Apache, i tre file sono stati riuniti in httpd.conf. Abbiamo già illustrato i punti salienti di questo file di configurazione. Negli esempi che seguono è stata utilizzata per i test la versione Apache di EasyPhp e, di conseguenza, il relativo file di configurazione. In esso, DocumentRoot, che indica la radice della struttura delle pagine web, è e:\program files\easyphp\www.

Per effettuare un test, creare il file intro.php contenente solo la seguente riga:

<? phpinfo() ?>

e inserirlo nella directory principale delle pagine del server Apache (DocumentRoot sopra indicato). Richiedere l'URL http://localhost/intro.php. Dovrebbe apparire un elenco di informazioni php:

Image

Il seguente script PHP visualizza l'ora. Lo abbiamo già visto in precedenza:

<?php
   // time: numero di millisecondi dal 01/01/1970
   // "formato di visualizzazione data-ora
   // d: giorno a 2 cifre
   // m: mese a 2 cifre
   // y: anno a 2 cifre
   // H: ora 0,23
   // i: minuti
   // s: secondi
  print "Nous sommes le " . date("d/m/y H:i:s",time());
?>

Mettiamo questo file di testo nella directory principale delle pagine del server Apache (DocumentRoot) e chiamiamolo date.php. Accediamo con un browser all’indirizzo http://localhost/date.php. Otteniamo la seguente pagina:

Image

Viene creato tramite una riga del tipo: ScriptAlias /cgi-bin/ "E:/Program Files/EasyPHP/cgi-bin/" nel file <apache>\conf\httpd.conf. La sua sintassi è ScriptAlias /cgi-bin/ "<cgi-bin>", dove <cgi-bin> è la cartella in cui è possibile inserire gli script CGI. CGI (Common Gateway Interface) è uno standard di comunicazione tra il server WEB e le applicazioni. Un client richiede al server Web una pagina dinamica, c.a.d, ovvero una pagina generata da un programma. Il server WEB deve quindi richiedere a un programma di generare la pagina. CGI definisce l’interazione tra il server e il programma, in particolare la modalità di trasmissione delle informazioni tra queste due entità.

Se necessario, modificate la riga ScriptAlias /cgi-bin/ "<cgi-bin>" e riavviate il server Apache. Eseguite quindi il seguente test:

  1. Scrivere lo script:
#!c:\perl\bin\perl.exe

# script PERL che visualizza l'ora

# moduli
use strict;

# programma
my ($secondes,$minutes,$heure)=localtime(time);
print <<FINHTML
Content-Type: text/html

<html>
 <head>
  <title>heure</title>
 </head>
 <body>
  <h1>Il est $heure:$minutes:$secondes</h1>
 </body>
FINHTML
;
  1. Inserire questo script in <cgi-bin>\heure.pl, dove <cgi-bin> è la cartella in cui possono essere inseriti gli script CGI (cfr. httpd.conf). La prima riga #!c:\perl\bin\perl.exe indica il percorso dell'eseguibile perl.exe. Modificarlo se necessario.
  2. Avviare Apache se non è già stato fatto
  3. Accedere con un browser all'indirizzo http://localhost/cgi-bin/heure.pl. Si otterrà la seguente pagina:

Image

8.1.9. Il server PWS

8.1.9.1. Installation

Il server PWS (Personal Web Server) è una versione personale del server IIS (Internet Information Server) di Microsoft. Quest'ultimo è disponibile sui sistemi NT e 2000. Sui sistemi Win9x, PWS è normalmente disponibile con il pacchetto di installazione di Internet Explorer. Tuttavia, non viene installato di default. È necessario eseguire un'installazione personalizzata di IE e richiedere l'installazione di PWS. È inoltre disponibile nel NT 4.0 Option Pack per Windows 95.

8.1.9.2. Primi test

La directory principale delle pagine Web del server PWS è unità:\inetpub\wwwroot, dove unità è il disco su cui è stato installato PWS. Di seguito supponiamo che tale unità sia D. Pertanto, l'URL http://machine/rep1/page1.html corrisponderà al file d:\inetpub\wwwroot\rep1\page1.html. Il server PWS interpreta ogni file con estensione .asp (Active Server Pages) come uno script da eseguire per generare una pagina HTML.

PWS opera per impostazione predefinita sulla porta 80. Anche il server web Apache... È quindi necessario arrestare Apache per poter utilizzare PWS se si dispone di entrambi i server. L'altra soluzione consiste nel configurare Apache affinché operi su una porta diversa. Pertanto, nel file di configurazione di Apache httpd.conf, si sostituisce la riga Port 80 con Port 81; Apache opererà d'ora in poi sulla porta 81 e potrà essere utilizzato contemporaneamente a PWS. Se PWS è stato avviato e si richiede l'accesso a URL http://localhost, si ottiene una pagina simile alla seguente:

Image

8.1.9.3. Collegamento PHP - PWS

  1. Di seguito è riportato un file .reg destinato a modificare il registro di sistema. Fare doppio clic su questo file per modificare il registro. In questo caso, il file dll necessario si trova in d:\php4 insieme all’eseguibile di PHP. Modificare se necessario. I caratteri \ devono essere duplicati nel percorso della DLL.
REGEDIT4

[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\w3svc\parameters\Script Map]
".php"="d:\\php4\\php4isapi.dll"
  1. Riavviare il sistema affinché la modifica del Registro di sistema venga applicata.
  1. Creare una cartella php in d:\inetpub\wwwroot, che è la radice del server PWS. Una volta fatto ciò, avviare PWS e selezionare la scheda «Avanzate». Selezionare il pulsante «Aggiungi» per creare una cartella virtuale:
Répertoire/Parcourir : d:\inetpub\wwwroot\php
Alias : php
Cocher la case exécuter.
  1. Confermare il tutto e riavviare PWS. Inserire in d:\inetpub\wwwroot\php il file intro.php contenente la seguente unica riga:
<? phpinfo() ?>
  1. Richiedere al server PWS il file URL http://localhost/php/intro.php. Dovrebbe apparire l'elenco delle informazioni PHP già visualizzate con Apache.

8.1.10. Tomcat: servlet Java e pagine JSP (Java Server Pages)

Tomcat è un server Web che consente di generare pagine HTML tramite servlet (programmi Java eseguiti dal server Web) o pagine JSP (Java Server Pages), ovvero pagine che combinano codice Java e codice HTML. Si tratta dell’equivalente delle pagine ASP (Active Server Pages) del server IIS/PWS di Microsoft, in cui si mescola codice VBScript o JavaScript con codice HTML.

8.1.10.1. Installation

Tomcat è disponibile all'indirizzo URL: http://jakarta.apache.org. Si scarica un file .exe di installazione. Quando si avvia questo programma, esso indica innanzitutto quale JDK utilizzerà. Infatti, Tomcat necessita di un JDK per installarsi e successivamente per compilare ed eseguire i servlet Java. È quindi necessario aver installato un JDK Java prima di installare Tomcat. Si consiglia di utilizzare il JD più recente. L’installazione creerà una struttura di directory <tomcat>:

Image

consiste semplicemente nel decomprimere questo archivio in una directory. Scegliete una directory il cui percorso contenga solo nomi senza spazi (ad esempio, non "Program Files"), poiché è presente un bug nel processo di installazione di Tomcat. Scegliete ad esempio C:\tomcat o D:\tomcat. Chiamiamo questa directory <tomcat>. Al suo interno troverete una cartella denominata jakarta-tomcat e, al suo interno, la seguente struttura:

LOGS           <REP>        15/11/00   9:04 logs
LICENSE              2 876  18/04/00  15:56 LICENSE
CONF           <REP>        15/11/00   8:53 conf
DOC            <REP>        15/11/00   8:53 doc
LIB            <REP>        15/11/00   8:53 lib
SRC            <REP>        15/11/00   8:53 src
WEBAPPS        <REP>        15/11/00   8:53 webapps
BIN            <REP>        15/11/00   8:53 bin
WORK           <REP>        15/11/00   9:04 work

8.1.10.2. Avvio/Arresto del server Web Tomcat

Tomcat è un server Web, proprio come Apache o PWS. Per avviarlo, sono disponibili dei collegamenti nel menu dei programmi:

Start Tomcat
per avviare Tomcat
Stop Tomcat
per arrestarlo

Quando si avvia Tomcat, viene visualizzata una finestra DOS con il seguente contenuto:

Image

È possibile ridurre a icona questa finestra DOS. Rimarrà aperta finché Tomcat sarà attivo. A questo punto è possibile procedere con i primi test. Il server Web Tomcat opera sulla porta 8080. Una volta avviato Tomcat, aprite un browser Web e digitate l'indirizzo http://localhost:8080. Dovreste visualizzare la seguente pagina:

Image

Seguite il link «Servlet Examples»:

Image

Clicca sul link Execute da RequestParameters, quindi su quello di Source. Avrete una prima panoramica su cosa sia un servlet Java. Potrete fare lo stesso con i link presenti nelle pagine JSP.

Per arrestare Tomcat, utilizzeremo il link “Stop Tomcat” nel menu dei programmi.

8.1.11. JBuilder

JBuilder è un ambiente di sviluppo per applicazioni Java. Per creare servlet Java in cui non sono presenti interfacce grafiche, non è indispensabile disporre di un ambiente di questo tipo. Sono sufficienti un editor di testo e un JDK. Tuttavia, JBuilder offre alcuni vantaggi rispetto alla tecnica precedente:

  • facilità di debug: il compilatore segnala le righe errate di un programma ed è facile individuarle
  • suggerimenti di codice: quando si utilizza un oggetto Java, JBuilder fornisce in linea l’elenco delle proprietà e dei metodi di quest’ultimo. Ciò è molto pratico se si considera che la maggior parte degli oggetti Java presenta un numero molto elevato di proprietà e metodi che è difficile ricordare.

JBuilder è disponibile sul sito http://www.borland.com/jbuilder. Per ottenere il software è necessario compilare un modulo. Una chiave di attivazione viene inviata via e-mail. Per installare JBuilder 7, ad esempio, si è proceduto come segue:

  • sono stati scaricati tre file zip: uno per l’applicazione, uno per la documentazione e uno per gli esempi. Ciascuno di questi file zip è raggiungibile tramite un link separato sul sito di JBuilder.
  • Si è installata prima l’applicazione, poi la documentazione e infine gli esempi
  • Quando si avvia l’applicazione per la prima volta, viene richiesta una chiave di attivazione: è quella che vi è stata inviata via e-mail. Nella versione 7, questa chiave è in realtà l’intero contenuto di un file di testo che può essere inserito, ad esempio, nella cartella di installazione di JB7. Nel momento in cui viene richiesta la chiave, si indica il file in questione. Una volta fatto ciò, la chiave non verrà più richiesta.

È necessario effettuare alcune configurazioni utili se si desidera utilizzare JBuilder per creare servlet Java. Infatti, la versione denominata «Jbuilder personale» è una versione ridotta che, in particolare, non include tutte le classi necessarie per lo sviluppo web in Java. È possibile fare in modo che JBuilder utilizzi le librerie di classi fornite da Tomcat. Si procede come segue:

  • avviare JBuilder

Image

  • attivare l’opzione Tools/Configure JDKs

Image

Nella sezione JDK Settings sopra riportata, normalmente nel campo Name è presente JDK 1.3.1. Se si dispone di una versione più recente di JDK, utilizzare il pulsante Change per specificare la directory di installazione di quest'ultima. Nell’esempio sopra riportato, è stata specificata la directory E:\Program Files\jdk14 in cui era stato installato un JDK 1.4. D’ora in poi, JBuilder utilizzerà questo JDK per le proprie compilazioni ed esecuzioni. Nella sezione (Class, Source, Documentation) è presente l’elenco di tutte le librerie di classi che saranno analizzate da JBuilder, in questo caso le classi di JDK 1.4. Le classi di quest’ultimo non sono sufficienti per lo sviluppo web in Java. Per aggiungere altre librerie di classi si utilizza il pulsante Add e si selezionano i file .jar aggiuntivi che si desidera utilizzare. I file .jar sono librerie di classi. Tomcat 4.x include tutte le librerie di classi necessarie per lo sviluppo web. Si trovano in <tomcat>\common\lib, dove <tomcat> è la directory di installazione di Tomcat:

Image

Con il pulsante Add, aggiungeremo queste librerie, una alla volta, all’elenco delle librerie esplorate da JBuilder:

Image

Da questo momento in poi, è possibile compilare programmi Java conformi allo standard J2EE, in particolare i servlet Java. JBuilder serve solo per la compilazione, mentre l’esecuzione è successivamente gestita da Tomcat secondo le modalità illustrate nel corso.

8.2. Codice sorgente dei programmi

8.2.1. Il client generico TCP

Molti servizi creati agli albori di Internet funzionano secondo il modello del server di eco studiato in precedenza: gli scambi client-server avvengono tramite lo scambio di righe di testo. Scriveremo un client TCP generico che verrà avviato nel modo seguente: java cltTCPgenerique server porta

Questo client TCP si connetterà alla porta port del server serveur. Una volta fatto ciò, creerà due thread:

  1. un thread incaricato di leggere i comandi digitati sulla tastiera e di inviarli al server
  2. un thread incaricato di leggere le risposte del server e di visualizzarle sullo schermo

Perché due thread? Ogni servizio TCP-IP ha un proprio protocollo specifico e talvolta si verificano le seguenti situazioni:

  • il client deve inviare più righe di testo prima di ricevere una risposta
  • la risposta di un server può contenere più righe di testo

Pertanto, il ciclo che prevede l’invio di una singola riga al server e la ricezione di una singola riga inviata dal server non è sempre adeguato. Creeremo quindi due cicli distinti:

  • un ciclo di lettura dei comandi digitati sulla tastiera da inviare al server. L’utente segnalerà la fine dei comandi con la parola chiave fin.
  • un ciclo di ricezione e visualizzazione delle risposte del server. Si tratterà di un ciclo infinito che verrà interrotto solo dalla chiusura del flusso di rete da parte del server o dall’utente tramite la tastiera, digitando il comando fin.

Per avere questi due cicli separati, abbiamo bisogno di due thread indipendenti. Vediamo un esempio di esecuzione in cui il nostro client TCP generico si connette a un servizio SMTP (SendMail Transfer Protocol). Questo servizio è responsabile dell’inoltro della posta elettronica ai destinatari. Funziona sulla porta 25 e utilizza un protocollo di comunicazione basato sullo scambio di righe di testo.

Dos>java clientTCPgenerique istia.univ-angers.fr 25
Commandes :
<-- 220 istia.univ-angers.fr ESMTP Sendmail 8.11.6/8.9.3; Mon, 13 May 2002 08:37:26 +0200
help
<-- 502 5.3.0 Sendmail 8.11.6 -- HELP not implemented
mail from: machin@univ-angers.fr
<-- 250 2.1.0 machin@univ-angers.fr... Sender ok
rcpt to: serge.tahe@istia.univ-angers.fr
<-- 250 2.1.5 serge.tahe@istia.univ-angers.fr... Recipient ok
data
<-- 354 Enter mail, end with "." on a line by itself
Subject: test

ligne1
ligne2
ligne3
.
<-- 250 2.0.0 g4D6bks25951 Message accepted for delivery
quit
<-- 221 2.0.0 istia.univ-angers.fr closing connection
[fin du thread de lecture des réponses du serveur]
fin
[fin du thread d'envoi des commandes au serveur]

Commentiamo questi scambi client-server:

  • il servizio SMTP invia un messaggio di benvenuto quando un client si connette ad esso:
<-- 220 istia.univ-angers.fr ESMTP Sendmail 8.11.6/8.9.3; Mon, 13 May 2002 08:37:26 +0200
  • alcuni servizi dispongono di un comando help che fornisce indicazioni sui comandi utilizzabili con il servizio. In questo caso non è così. I comandi SMTP utilizzati nell'esempio sono i seguenti:
    • mail from: expéditeur, per indicare l’indirizzo e-mail del mittente del messaggio
    • rcpt to: destinataire, per indicare l’indirizzo e-mail del destinatario del messaggio. Se ci sono più destinatari, il comando rcpt to: va ripetuto tante volte quante necessarie per ciascuno di essi.
    • data, che segnala al server SMTP che si sta per inviare il messaggio. Come indicato nella risposta del server, il messaggio è costituito da una sequenza di righe terminata da una riga contenente il solo carattere punto. Un messaggio può avere delle intestazioni separate dal corpo del messaggio da una riga vuota. Nel nostro esempio, abbiamo inserito un oggetto con la parola chiave Subject:
  • una volta inviato il messaggio, è possibile indicare al server che si è terminato con il comando quit. Il server chiude quindi la connessione di rete. Il thread di lettura può rilevare questo evento e arrestarsi.
  • L’utente digita quindi «fin» sulla tastiera per arrestare anche il thread di lettura dei comandi digitati sulla tastiera.

Se controlliamo la posta ricevuta, troviamo quanto segue (Outlook):

Image

Si noti che il servizio SMTP non è in grado di rilevare se un mittente sia valido o meno. Pertanto, non ci si può mai fidare del campo from di un messaggio. In questo caso, il mittente machin@univ-angers.fr non esisteva.

Questo client TCP generico ci permette di individuare il protocollo di comunicazione dei servizi Internet e, partendo da lì, di creare classi specializzate per i client di tali servizi. Scopriamo il protocollo di comunicazione del servizio POP (Post Office Protocol), che consente di recuperare le proprie e-mail archiviate su un server. Funziona sulla porta 110.

Dos> java clientTCPgenerique istia.univ-angers.fr 110
Commandes :
<-- +OK Qpopper (version 4.0.3) at istia.univ-angers.fr starting.
help
<-- -ERR Unknown command: "help".
user st
<-- +OK Password required for st.
pass monpassword
<-- +OK st has 157 visible messages (0 hidden) in 11755927 octets.
list
<-- +OK 157 visible messages (11755927 octets)
<-- 1 892847
<-- 2 171661
...
<-- 156 2843
<-- 157 2796
<-- .
retr 157
<-- +OK 2796 octets
<-- Received: from lagaffe.univ-angers.fr (lagaffe.univ-angers.fr [193.49.144.1])
<--     by istia.univ-angers.fr (8.11.6/8.9.3) with ESMTP id g4D6wZs26600;
<--     Mon, 13 May 2002 08:58:35 +0200
<-- Received: from jaume ([193.49.146.242])
<--     by lagaffe.univ-angers.fr (8.11.1/8.11.2/GeO20000215) with SMTP id g4D6wSd37691;
<--     Mon, 13 May 2002 08:58:28 +0200 (CEST)
...
<-- ------------------------------------------------------------------------
<-- NOC-RENATER2                  Tl.  : 0800 77 47 95
<-- Fax : (+33) 01 40 78 64 00 ,  Email : noc-r2@cssi.renater.fr
<-- ------------------------------------------------------------------------
<--
<-- .
quit
<-- +OK Pop server at istia.univ-angers.fr signing off.
[fin du thread de lecture des réponses du serveur]
fin
[fin du thread d'envoi des commandes au serveur]

I comandi principali sono i seguenti:

  • user login, dove si inserisce il proprio nome utente sul computer che ospita le nostre e-mail
  • pass password, dove si inserisce la password associata al login precedente
  • list, per ottenere l'elenco dei messaggi sotto forma di numero e dimensione in byte
  • retr i, per leggere il messaggio n. i
  • quit, per terminare la sessione.

Scopriamo ora il protocollo di comunicazione tra un client e un server Web che solitamente opera sulla porta 80:

Dos> java clientTCPgenerique istia.univ-angers.fr 80
Commandes :
GET /index.html HTTP/1.0

<-- HTTP/1.1 200 OK
<-- Date: Mon, 13 May 2002 07:30:58 GMT
<-- Server: Apache/1.3.12 (Unix)  (Red Hat/Linux) PHP/3.0.15 mod_perl/1.21
<-- Last-Modified: Wed, 06 Feb 2002 09:00:58 GMT
<-- ETag: "23432-2bf3-3c60f0ca"
<-- Accept-Ranges: bytes
<-- Content-Length: 11251
<-- Connection: close
<-- Content-Type: text/html
<--
<-- <html>
<--
<-- <head>
<-- <meta http-equiv="Content-Type"
<-- content="text/html; charset=iso-8859-1">
<-- <meta name="GENERATOR" content="Microsoft FrontPage Express 2.0">
<-- <title>Bienvenue a l'ISTIA - Universite d'Angers</title>
<-- </head>
....
<-- face="Verdana"> - Dernire mise  jour le <b>10 janvier 2002</b></font></p>
<-- </body>
<-- </html>
<--
[fin du thread de lecture des réponses du serveur]
fin
[fin du thread d'envoi des commandes au serveur]

Un client Web invia i propri comandi al server secondo lo schema seguente:

commande1
commande2
...
commanden
[ligne vide]

Il server Web risponde solo dopo aver ricevuto la riga vuota. Nell'esempio abbiamo utilizzato un solo comando:

GET /index.html HTTP/1.0

che richiede al server il file URL /index.html e indica che sta operando con il protocollo HTTP versione 1.0. La versione più recente di questo protocollo è la 1.1. L'esempio mostra che il server ha risposto inviando il contenuto del file index.html e poi ha chiuso la connessione, poiché si vede che il thread di lettura delle risposte si è concluso. Prima di inviare il contenuto del file index.html, il server web ha inviato una serie di intestazioni terminata da una riga vuota:

<-- HTTP/1.1 200 OK
<-- Date: Mon, 13 May 2002 07:30:58 GMT
<-- Server: Apache/1.3.12 (Unix)  (Red Hat/Linux) PHP/3.0.15 mod_perl/1.21
<-- Last-Modified: Wed, 06 Feb 2002 09:00:58 GMT
<-- ETag: "23432-2bf3-3c60f0ca"
<-- Accept-Ranges: bytes
<-- Content-Length: 11251
<-- Connection: close
<-- Content-Type: text/html
<--
<-- <html>

La riga <html> è la prima riga del file /index.html. Quanto sopra è denominato intestazioni HTTP (HyperText Transfer Protocol). Non entreremo qui nei dettagli di queste intestazioni, ma ricordiamo che il nostro client generico ne consente l’accesso, il che può essere utile per comprenderle. Ad esempio, la prima riga:

<-- HTTP/1.1 200 OK

indica che il server Web contattato supporta il protocollo HTTP/1.1 e che ha effettivamente trovato il file richiesto (200 OK), dove 200 è un codice di risposta HTTP. Le righe

<-- Content-Length: 11251
<-- Connection: close
<-- Content-Type: text/html

indicano al client che riceverà 11251 byte corrispondenti al testo HTML (HyperText Markup Language) e che, al termine dell’invio, la connessione verrà chiusa.

Abbiamo quindi un client TCP molto pratico. Sicuramente offre meno funzionalità rispetto al programma ufficiale telnet, ma è stato interessante scriverlo da soli. Il codice del client TCP generico è il seguente:

// pacchetti importati
import java.io.*;
import java.net.*;

public class clientTCPgenerique{

    // riceve come parametro le caratteristiche di un servizio nella forma
     // server porta
     // si connette al servizio
     // crea un thread per leggere i comandi digitati sulla tastiera
     // questi verranno inviati al server
     // crea un thread per leggere le risposte del server
     // queste verranno visualizzate sullo schermo
     // il tutto termina con il comando «fine» digitato sulla tastiera

   // variabile di istanza
  private static Socket client;

    public static void main(String[] args){

         // sintassi
        final String syntaxe="pg serveur port";

         // numero di argomenti
        if(args.length != 2)
            erreur(syntaxe,1);

         // si annota il nome del server
        String serveur=args[0];

         // la porta deve essere un numero intero >0
        int port=0;
        boolean erreurPort=false;
        Exception E=null;
        try{
            port=Integer.parseInt(args[1]);
        }catch(Exception e){
            E=e;
            erreurPort=true;
        }
        erreurPort=erreurPort || port <=0;
        if(erreurPort)
            erreur(syntaxe+"\n"+"Port incorrect ("+E+")",2);

        client=null;
         // potrebbero verificarsi dei problemi
        try{
             // si effettua la connessione al servizio
            client=new Socket(serveur,port);
        }catch(Exception ex){
             // errore
            erreur("Impossible de se connecter au service ("+ serveur
                +","+port+"), erreur : "+ex.getMessage(),3);
             // fine
            return;
        }//catch

         // si creano i thread di lettura/scrittura
    new ClientSend(client).start();
    new ClientReceive(client).start();

         // fine thread principale
        return;
    }// main

     // visualizzazione degli errori
    public static void erreur(String msg, int exitCode){
         // visualizzazione dell'errore
        System.err.println(msg);
         // arresto con errore
        System.exit(exitCode);
    }//errore
}//classe  

class ClientSend extends Thread {
    // classe incaricata di leggere i comandi digitati sulla tastiera
     // e di inviarli a un server tramite un client TCP passato come parametro

    private Socket client;    // il client TCP

     // costruttore
    public ClientSend(Socket client){
         // si nota il client TCP
        this.client=client;
    }//costruttore

     // metodo Run del thread
    public void run(){

        // dati locali
        PrintWriter OUT=null;            // flusso di scrittura di rete
    BufferedReader IN=null;        // flusso da tastiera
        String commande=null;            // comando letto dalla tastiera

         // gestione degli errori
        try{
             // creazione del flusso di scrittura di rete
            OUT=new PrintWriter(client.getOutputStream(),true);
      // creazione del flusso di input da tastiera
      IN=new BufferedReader(new InputStreamReader(System.in));
            // ciclo di immissione e invio dei comandi
            System.out.println("Commandes : ");
            while(true){
                 // lettura del comando digitato sulla tastiera
                commande=IN.readLine().trim();
                 // finito?
                if (commande.toLowerCase().equals("fin")) break;
                // invio del comando al server
                OUT.println(commande);
                 // comando successivo
            }//while
        }catch(Exception ex){
             // errore
            System.err.println("Envoi : L'erreur suivante s'est produite : " + ex.getMessage());
        }//catch
         // fine - si chiudono i flussi
        try{
            OUT.close();client.close();
        }catch(Exception ex){}
         // si segnala la fine del thread
        System.out.println("[Envoi : fin du thread d'envoi des commandes au serveur]");
    }//run
}//classe

class ClientReceive extends Thread{
    // classe incaricata di leggere le righe di testo destinate a un 
     // client TCP passato come parametro

    private Socket client;    // il client TCP

     // costruttore
    public ClientReceive(Socket client){
         // si registra il client TCP
        this.client=client;
    }//costruttore

     // metodo Run del thread
    public void run(){

        // dati locali
        BufferedReader IN=null;        // flusso di lettura di rete
        String réponse=null;        // risposta del server

         // gestione degli errori
        try{
             // creazione del flusso di lettura di rete
            IN=new BufferedReader(new InputStreamReader(client.getInputStream()));
            // ciclo di lettura delle righe di testo del flusso IN
            while(true){
                 // lettura del flusso di rete
                réponse=IN.readLine();
                 // flusso chiuso?
                if(réponse==null) break;
                // visualizzazione
                System.out.println("<-- "+réponse);
            }//while
        }catch(Exception ex){
            // errore
            System.err.println("Réception : L'erreur suivante s'est produite : " + ex.getMessage());
        }//catch
         // fine - si chiudono i flussi
        try{
            IN.close();client.close();
        }catch(Exception ex){}
         // si segnala la fine del thread
        System.out.println("[Réception : fin du thread de lecture des réponses du serveur]");
    }//run
}//classe

8.2.2. Il server TCP generico

Ora ci occupiamo di un server

  • che visualizza sullo schermo i comandi inviati dai propri client
  • e invia loro in risposta le righe di testo digitate sulla tastiera da un utente. È quindi quest’ultimo a fungere da server.

Il programma viene avviato con: java serveurTCPgenerique portEcoute, dove portEcoute è la porta a cui i client devono connettersi. Il servizio al client sarà gestito da due thread:

  • un thread dedicato esclusivamente alla lettura delle righe di testo inviate dal client
  • un thread dedicato esclusivamente alla lettura delle risposte digitate dall’utente sulla tastiera. Quest’ultimo segnalerà, tramite il comando «fin», la chiusura della connessione con il client.

Il server crea due thread per ogni client. Se ci sono n client, ci saranno 2n thread attivi contemporaneamente. Il server, dal canto suo, non si arresta mai, a meno che l’utente non prema Ctrl-C sulla tastiera. Vediamo alcuni esempi.

Il server viene avviato sulla porta 100 e si utilizza il client generico per comunicare con esso. La finestra del client è la seguente:

E:\data\serge\MSNET\c#\rete\client tcp generico> java clientTCPgenerique localhost 100
Commandes :
commande 1 du client 1
<-- réponse 1 au client 1
commande 2 du client 1
<-- réponse 2 au client 1
fin
L'erreur suivante s'est produite : Impossible de lire les données de la connexion de transport.
[fin du thread de lecture des réponses du serveur]
[fin du thread d'envoi des commandes au serveur]

Le righe che iniziano con <-- sono quelle inviate dal server al client, le altre sono quelle inviate dal client al server. La finestra del server è la seguente:


Dos> java serveurTCPgenerique 100
Serveur générique lancé sur le port 100
Thread de lecture des réponses du serveur au client 1 lancé
1 : Thread de lecture des demandes du client 1 lancé
<-- commande 1 du client 1
réponse 1 au client 1
1 : <-- commande 2 du client 1
réponse 2 au client 1
1 : [fin du Thread de lecture des demandes du client 1]
fin
[fin du Thread de lecture des réponses du serveur au client 1]

Le righe che iniziano con <-- sono quelle inviate dal client al server. Le righe N: sono quelle inviate dal server al client n. N. Il server sopra indicato è ancora attivo, mentre il client 1 ha terminato l'operazione. Si avvia un secondo client per lo stesso server:


Dos> java clientTCPgenerique localhost 100
Commandes :
commande 3 du client 2
<-- réponse 3 au client 2
fin
L'erreur suivante s'est produite : Impossible de lire les données de la connexion de transport.
[fin du thread de lecture des réponses du serveur]
[fin du thread d'envoi des commandes au serveur]

La finestra del server appare quindi così:


Dos> java serveurTCPgenerique 100
Serveur générique lancé sur le port 100
Thread de lecture des réponses du serveur au client 1 lancé
1 : Thread de lecture des demandes du client 1 lancé
<-- commande 1 du client 1
réponse 1 au client 1
1 : <-- commande 2 du client 1
réponse 2 au client 1
1 : [fin du Thread de lecture des demandes du client 1]
fin
[fin du Thread de lecture des réponses du serveur au client 1]
Thread de lecture des réponses du serveur au client 2 lancé
2 : Thread de lecture des demandes du client 2 lancé
<-- commande 3 du client 2
réponse 3 au client 2
2 : [fin du Thread de lecture des demandes du client 2]
fin
[fin du Thread de lecture des réponses du serveur au client 2]
^C

Simuliamo ora un server web avviando il nostro server generico sulla porta 88:


Dos> java serveurTCPgenerique 88
Serveur générique lancé sur le port 88

Apriamo ora un browser e richiediamo l'http://localhost:88/exemple.html URL. Il browser si connetterà quindi alla porta 88 del computer localhost e richiederà la pagina /exemple.html:

Image

Diamo ora un’occhiata alla finestra del nostro server:

Dos>java serveurTCPgenerique 88
Serveur générique lancé sur le port 88
Thread de lecture des réponses du serveur au client 2 lancé
2 : Thread de lecture des demandes du client 2 lancé
<-- GET /exemple.html HTTP/1.1
<-- Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, application/msword, */*
<-- Accept-Language: fr
<-- Accept-Encoding: gzip, deflate
<-- User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; .NET CLR 1.0.3705; .NET CLR 1.0.2
914)
<-- Host: localhost:88
<-- Connection: Keep-Alive
<--

Si scoprono così le intestazioni HTTP inviate dal browser. Questo ci permette di scoprire poco a poco il protocollo HTTP. In un esempio precedente, avevamo creato un client Web che inviava solo il comando GET. Era stato sufficiente. Qui vediamo che il browser invia altre informazioni al server. Il loro scopo è indicare al server quale tipo di client ha di fronte. Notiamo inoltre che le intestazioni HTTP terminano con una riga vuota.

Elaboriamo una risposta per il nostro client. L’utente alla tastiera è in questo caso il vero server e può elaborare una risposta manualmente. Ricordiamo la risposta fornita da un server Web in un esempio precedente:

<-- HTTP/1.1 200 OK
<-- Date: Mon, 13 May 2002 07:30:58 GMT
<-- Server: Apache/1.3.12 (Unix)  (Red Hat/Linux) PHP/3.0.15 mod_perl/1.21
<-- Last-Modified: Wed, 06 Feb 2002 09:00:58 GMT
<-- ETag: "23432-2bf3-3c60f0ca"
<-- Accept-Ranges: bytes
<-- Content-Length: 11251
<-- Connection: close
<-- Content-Type: text/html
<--
<-- <html>

Proviamo a dare una risposta analoga:

...
<-- Host: localhost:88
<-- Connection: Keep-Alive
<--
2 : HTTP/1.1 200 OK
2 : Server: serveur tcp generique
2 : Connection: close
2 : Content-Type: text/html
2 :
2 : <html>
2 :   <head><title>Serveur generique</title></head>
2 :   <body>
2 :     <center>
2 :       <h2>Reponse du serveur generique</h2>
2 :     </center>
2 :    </body>
2 : </html>
2 : fin
L'erreur suivante s'est produite : Impossible de lire les données de la connexion de transport.
[fin du Thread de lecture des demandes du client 2]
[fin du Thread de lecture des réponses du serveur au client 2]

Le righe che iniziano con 2: vengono inviate dal server al client n. 2. Il comando fin chiude la connessione tra il server e il client. Nella nostra risposta ci siamo limitati alle seguenti intestazioni HTTP:

HTTP/1.1 200 OK
2 : Server: serveur tcp generique
2 : Connection: close
2 : Content-Type: text/html
2 :

Non specifichiamo la dimensione del file che stiamo per inviare (Content-Length), ma ci limitiamo a indicare che chiuderemo la connessione (Connection: close) dopo averlo inviato. Questo è sufficiente per il browser. Quando rileva che la connessione è stata chiusa, il browser capirà che la risposta del server è terminata e visualizzerà la pagina HTML che gli è stata inviata. Quest'ultima è la seguente:

2 : <html>
2 :   <head><title>Serveur generique</title></head>
2 :   <body>
2 :     <center>
2 :       <h2>Reponse du serveur generique</h2>
2 :     </center>
2 :    </body>
2 : </html>

L'utente chiude quindi la connessione al client digitando il comando fin. Il browser capisce così che la risposta del server è terminata e può quindi visualizzarla:

Image

Se, come sopra, si esegue il comando View/Source per vedere cosa ha ricevuto il browser, si ottiene:

Image

ovvero esattamente ciò che è stato inviato dal server generico.

Il codice del server TCP generico è il seguente:

// pacchetti
import java.io.*;
import java.net.*;

public class serveurTCPgenerique{

     // programma principale
    public static void main (String[] args){

    // riceve le richieste dei client sulla porta di ascolto
     // crea un thread per leggere le richieste del client
     // queste verranno visualizzate sullo schermo
     // crea un thread per leggere i comandi digitati sulla tastiera
     // questi saranno inviati come risposta al cliente
     // il tutto termina con il comando «fine» digitato sulla tastiera

    final String syntaxe="Syntaxe : pg port";
   // variabile di istanza
         // c'è un argomento
     if(args.length != 1)
        erreur(syntaxe,1);

         // la porta deve essere un numero intero >0
        int port=0;
        boolean erreurPort=false;
        Exception E=null;
        try{
            port=Integer.parseInt(args[0]);
        }catch(Exception e){
            E=e;
            erreurPort=true;
        }
        erreurPort=erreurPort || port <=0;
        if(erreurPort)
            erreur(syntaxe+"\n"+"Port incorrect ("+E+")",2);

     // si crea il servizio di ascolto
    ServerSocket ecoute=null;
    int nbClients=0;    // numero di client gestiti
        try{
             // si crea il servizio
            ecoute=new ServerSocket(port);
             // monitoraggio
            System.out.println("Serveur générique lancé sur le port " + port);

             // ciclo di servizio ai clienti
            Socket client=null;
            while (true){ // ciclo infinito - verrà interrotto con Ctrl-C
                 // in attesa di un cliente
                client=ecoute.accept();

                 // il servizio è gestito da thread separati
                nbClients++;

                 // vengono creati i thread di lettura/scrittura
        new ServeurSend(client,nbClients).start();
        new ServeurReceive(client,nbClients).start();

                // si torna ad ascoltare le richieste
            }// fine ciclo while
        }catch(Exception ex){
             // si segnala l'errore
            erreur("L'erreur suivante s'est produite : " + ex.getMessage(),3);
        }//catch
    }// fine main

     // visualizzazione degli errori
    public static void erreur(String msg, int exitCode){
         // visualizzazione dell'errore
        System.err.println(msg);
         // arresto con errore
        System.exit(exitCode);
    }//errore
}//classe

class ServeurSend extends Thread{
    // classe incaricata di leggere le risposte digitate sulla tastiera
     // e di inviarle a un client tramite un client TCP passato al costruttore

    Socket client;    // il client TCP
    int numClient;        // numero del client

     // costruttore
    public ServeurSend(Socket client, int numClient){
         // si annota il client TCP
        this.client=client;
         // e il relativo n.
        this.numClient=numClient;
    }//produttore

     // metodo Run del thread
    public void run(){

        // dati locali
        PrintWriter OUT=null;        // flusso di scrittura di rete
        String réponse=null;        // risposta letta dalla tastiera
    BufferedReader IN=null;    // flusso da tastiera

        // monitoraggio
        System.out.println("Thread de lecture des réponses du serveur au client "+ numClient + " lancé");
         // gestione degli errori
        try{
             // creazione del flusso di scrittura di rete
            OUT=new PrintWriter(client.getOutputStream(),true);
      // creazione del flusso da tastiera
      IN=new BufferedReader(new InputStreamReader(System.in));
            // ciclo di immissione e invio dei comandi
            while(true){
                 // identificazione del cliente
                System.out.print("--> " + numClient + " : ");
                 // Lettura della risposta digitata sulla tastiera
                réponse=IN.readLine().trim();
                // finito?
                if (réponse.toLowerCase().equals("fin")) break;
                // invio della risposta al server
                OUT.println(réponse);
                 // risposta successiva
            }//while
        }catch(Exception ex){
             // errore
            System.err.println("L'erreur suivante s'est produite : " + ex.getMessage());
        }//catch
         // fine - si chiudono i flussi
        try{
            OUT.close();client.close();
        }catch(Exception ex){}
         // si segnala la fine del thread
        System.out.println("[fin du Thread de lecture des réponses du serveur au client "+ numClient+ "]");
    }//run
}//classe

class ServeurReceive extends Thread{
    // classe incaricata di leggere le righe di testo inviate al server 
     // tramite un client TCP passato al costruttore

    Socket client;    // il client TCP
    int numClient;        // numero del client

     // costruttore
    public ServeurReceive(Socket client, int numClient){
         // si registra il client TCP
        this.client=client;
         // e il suo n.
        this.numClient=numClient;
    }//produttore

     // metodo Run del thread
    public void run(){

        // dati locali
        BufferedReader IN=null;        // flusso di lettura di rete
        String réponse=null;        // risposta del server

         // monitoraggio
        System.out.println("Thread de lecture des demandes du client "+ numClient + " lancé");
         // gestione degli errori
        try{
             // creazione del flusso di lettura di rete
            IN=new BufferedReader(new InputStreamReader(client.getInputStream()));
            // ciclo di lettura delle righe di testo del flusso IN
            while(true){
                 // lettura flusso di rete
                réponse=IN.readLine();
                 // flusso chiuso?
                if(réponse==null) break;
                // visualizzazione
                System.out.println("<-- "+réponse);
            }//while
        }catch(Exception ex){
            // errore
            System.err.println("L'erreur suivante s'est produite : " + ex.getMessage());
        }//catch
         // fine - si chiudono i flussi
        try{
            IN.close();client.close();
        }catch(Exception ex){}
         // si segnala la fine del thread
        System.out.println("[fin du Thread de lecture des demandes du client "+ numClient+"]");
    }//run
}//classe

8.3. JAVASCRIPT

In questa sezione illustriamo tre esempi di utilizzo di JavaScript nelle pagine WEB. Ci concentriamo sulla gestione dei moduli, ma JavaScript può fare molto di più.

8.3.1. Recuperare le informazioni da un modulo

L'esempio riportato di seguito mostra come recuperare all'interno del browser i dati inseriti dall'utente in un modulo. Ciò consente in genere di effettuare operazioni di pre-elaborazione prima di inviarli al server.

8.3.1.1. Il modulo

Abbiamo un modulo che riunisce i componenti più comuni e un pulsante «Visualizza» che consente di visualizzare i dati inseriti dall’utente.

Image

8.3.1.2. Il codice

<html>

  <head>
    <title>Un formulaire traité par Javascript</title>
    <script language="javascript">
      function afficher(){
         // visualizza in un elenco le informazioni del modulo

         // si cancella prima
        effacerInfos();

         // si visualizza il valore dei # campi
        with(document.frmExemple){
           // campo nascosto
          ecrire("champ caché="+cache.value);
           // campo di testo singolo
          ecrire("champ textuel simple="+simple.value);
           // campo di testo multiplo
          ecrire("champ textuel multiple="+lignes.value);
          // pulsanti di opzione
          for(i=0;i<radio.length;i++){
            texte="radio["+i+"]="+radio[i].value;
            if(radio[i].checked) texte+=", coché";
            ecrire(texte);
          }//for
             // caselle di controllo
          for(i=0;i<qcm.length;i++){
            texte="qcm["+i+"]="+qcm[i].value;
            if(qcm[i].checked) texte+=", coché";
            ecrire(texte);
          }//for
           //elenco a discesa
          ecrire("index sélectionné dans le menu="+menu.selectedIndex);
          for(i=0;i<menu.length;i++){
            texte="menu["+i+"]="+menu.options[i].text;
            if(menu.options[i].selected) texte+=",sélectionné";
            ecrire(texte);
          }//per
           //elenco a scelta multipla
          for(i=0;i<lstVoitures.length;i++){
            texte="lstVoitures["+i+"]="+lstVoitures.options[i].text;
            if(lstVoitures.options[i].selected) texte+=",sélectionné";
            ecrire(texte);
          }//per
           //password
          ecrire("mot de passe="+passwd.value);
        }//con
      }//funzione

      function ecrire(texte){
         // scrive il testo nell'elenco delle informazioni
        frmInfos.lstInfos.options[frmInfos.lstInfos.length]=new Option(texte);
      }//scrivere

      function effacerInfos(){
        frmInfos.lstInfos.length=0;
      }//effacerInfos
    </script>
  </head>

  <body bgcolor="#C0C0C0" onload="afficher()">
    <center>
     <h2>Un formulaire traité par Javascript</h2>
    <hr>
    <form method="POST" name="frmExemple">
        <input type="hidden" name="cache" value="secret">
        <table border="0">
        <tr>
            <td align="center">Un champ textuel simple</td>
            <td align="center" width="100">&nbsp;</td>
            <td align="center">Un champ textuel sur plusieurs lignes</td>
        </tr>
        <tr>
            <td align="center"><input type="text" size="20" name="simple"></td>
            <td align="center" width="100">&nbsp;</td>
            <td align="center">
              <textarea name="lignes" rows="2" cols="40">Ce texte est modifiable</textarea>
            </td>
        </tr>
    </table>
    <table border="0">
      <tr>
       <td><strong>Des boutons radio :</strong></td>
        <td>
          <input type="radio" checked name="radio" value="FM">FM
        </td>
        <td>
          <input type="radio" name="radio" value="GO">GO
        </td>
        <td>
          <input type="radio" name="radio" value="PO">PO
        </td>
        <td>&nbsp;</td>
        <td><strong>Des choix multiples :</strong></td>
        <td>
          <input type="checkbox" name="qcm" value="un">un
        </td>
        <td>
          <input type="checkbox" name="qcm" value="deux">deux
        </td>
        <td>
          <input type="checkbox" name="qcm" value="trois">trois
        </td>
     </tr>
    </table>
    <table border="0">
      <tr>
       <td>Un menu déroulant : </td>
        <td>
          <select name="menu" size="1">
             <option>50 F</option>
              <option>60 F</option>
              <option>70 F</option>
              <option>100 F</option>
            </select>
        </td>
          <td>Une liste :</td>
           <td>
             <select name="lstVoitures" multiple size="3">
                <option>Renault</option>
                <option>Citroën</option>
                <option>Peugeot</option>
                <option>Fiat</option>
                <option>Audi</option>
              </select>
           </td>
        </tr>
    </table>
    <table border="0">
        <tr>
            <td>Un mot de passe : </td>
            <td><input type="password" size="21" name="passwd"></td>
            <td>&nbsp;</td>
            <td>Un champ de contexte caché : </td>
        </tr>
    </table>
    </form>
    <hr>
    <h2>Informations du formulaire</h2>
    <form name="frmInfos">
      <table>
        <tr>
          <td><input type="button" value="Effacer" onclick="effacerInfos()"></td>
          <td>
            <select name="lstInfos" multiple size="3">
            </select>
          </td>
          <td>
            <input type="button" name="cmdAfficher" value="Afficher" onclick="afficher()">
          </td>
        </tr>
    </form>
  </body>
</html>

8.3.2. Espressioni regolari in JavaScript

A livello di browser, JavaScript può essere utilizzato per verificare la validità dei dati inseriti dall'utente prima di inviarli al server. Ecco un programma di test per queste espressioni regolari.

8.3.2.1. La pagina di test

Image

8.3.2.2. Il codice della pagina

<html>

  <head>
    <title>Les expressions régulières en Javascript</title>
    <script language="javascript">
      function afficherInfos(){
        with(document.frmRegExp){
           // c'è qualcosa da fare?
          if (! verifier()) return;
          // Va bene - si cancellano i risultati precedenti
          effacerInfos();
           // verifica del modello
          modele=new RegExp(txtModele.value);
          champs=modele.exec(txtChaine.value);
          if(champs==null)
             // nessuna corrispondenza tra modello e stringa
            ecrireInfos("pas de correspondance");
          else{
             // corrispondenza - si visualizzano i risultati ottenuti
            ecrireInfos("Il y a correspondance");
            for(i=0;i<champs.length;i++)
              ecrireInfos("champs["+i+"]=["+champs[i]+"]");
          }//altrimenti
        }//con
      }//funzione

      function ecrireInfos(texte){
        // scrive il testo nell'elenco delle informazioni
        document.frmRegExp.lstInfos.options[document.frmRegExp.lstInfos.length]=new Option(texte);
      }//scrivere

      function effacerInfos(){
        frmRegExp.lstInfos.length=0;
      }//effacerInfos

      function jouer(){
         // verifica la corrispondenza del modello con la stringa nell'esempio selezionato
        with(document.frmRegExp){
          txtModele.value=lstModeles.options[lstModeles.selectedIndex].text
          txtChaine.value=lstChaines.options[lstChaines.selectedIndex].text
          afficherInfos();
        }//con
      }//riproduci

      function ajouter(){
         //aggiunge il test corrente agli esempi
        with(document.frmRegExp){
          // c'è qualcosa da fare?
          if (! verifier()) return;
           // aggiunta
          lstModeles.options[lstModeles.length]=new Option(txtModele.value);
          lstChaines.options[lstChaines.length]=new Option(txtChaine.value);
           // azzeramento degli inserimenti
          txtModele.value="";
          txtChaine.value="";
        }//con
      }//aggiungere

      function verifier(){
         // verifica che i campi di inserimento non siano vuoti
        with(document.frmRegExp){
          champs=/^\s*$/.exec(txtModele.value);
          if(champs!=null){
            alert("Vous n'avez pas indiqué de modèle");
            txtModele.focus();
            return false;
          }//se
          champs=/^\s*$/.exec(txtChaine.value);
          if(champs!=null){
            alert("Vous n'avez pas indiqué de chaîne de test");
            txtChaine.focus();
            return false;
          }//se
           // va bene
          return true;
        }//con
      }//verificare
    </script>
  </head>

  <body bgcolor="#C0C0C0">
    <center>
     <h2>Les expressions régulières en Javascript</h2>
    <hr>
    <form name="frmRegExp">
      <table>
        <tr>
          <td>Expression régulière</td>
          <td>Chaîne de test</td>
        </tr>
        <tr>
          <td><input type="text" name="txtModele" size="20"></td>
          <td><input type="text" name="txtChaine" size="20"></td>
        </tr>
        <tr>
          <td>
            <input type="button" name="cmdAfficher" value="Jouer le test" onclick="afficherInfos()">
          </td>
          <td>
            <input type="button" name="cmdAjouter" value="Ajouter aux exemples" onclick="ajouter()">
          </td>
        </tr>
      </table>
      <hr>
      <h2>Résultats de l'instruction champs=expression régulière.exec(chaine)</h2>
      <table>
        <tr>
          <td>
            <select name="lstInfos" size="3">
            </select>
          </td>
        </tr>
      </table>
      <hr>
      <h2>Exemples</h2>
      <table>
 <tr>
          <td align="center">Modèles</td>
          <td align="center">Chaînes</td>
        </tr>
        <tr>
          <td>
            <select name="lstModeles" size="1">
              <option>^\d+$</option>
              <option>^(\d+) (\d+)$</option>
              <option>^(\d+)(.*)(\d+)$</option>
              <option>^(\d+)(\s+)(\d+)$</option>
            </select>
          </td>
          <td>
            <select name="lstChaines" size="1">
              <option>67</option>
              <option>56 84</option>
              <option>45abcd67</option>
              <option>45   67</option>
            </select>
          </td>
          <td>
            <input type="button" name="cmdJouer" value="Jouer l'exemple" onclick="jouer()">
          </td>
        </tr>
    </form>
  </body>
</html>

8.3.3. Gestione delle liste in JavaScript

8.3.3.1. Il modulo

Image

8.3.3.2. Il codice

<html>

  <head>
    <title>Les listes en Javascript</title>

    <script language="javascript">
       // aggiungere
      function ajouter(L1,L2,T){
         // aggiunge il valore del campo T alle liste L1,L2
           // c'è qualcosa da fare?
          champs=/^\s*$/.exec(T.value);
          if(champs!=null){
            // il campo è vuoto
            alert("Vous n'avez pas indiqué la valeur à ajouter");
            txtElement.focus();
            return;
          }//if
           // si aggiunge l'elemento
          L1.options[L1.length]=new Option(T.value);
          L2.options[L2.length]=new Option(T.value);
          T.value="";
      }//aggiungere

       //svuotare
      function vider(L){
         // svuota la lista L
        L.length=0;
      }//svuota

      //trasferisce
      function transfert(L1,L2,simple){
        //trasferisce in L2 gli elementi selezionati nell'elenco L1

         // c'è qualcosa da fare?
         // indice dell'elemento selezionato in L1
        index1=L1.selectedIndex;
        if(index1==-1){
          alert("Vous n'avez pas sélectionné d'élément");
          return;
        }//if
         // Qual è la modalità di selezione degli elementi delle liste
        if(simple){ // selezione singola
          element1=L1.options[index1].text;
           //aggiunta in L2
          L2.options[L2.length]=new Option(element1);
          //eliminazione in L1
          L1.options[index1]=null;
        }//semplice
        if(! simple){ //selezione multipla
           //si scorre l'elenco 1 in ordine inverso
          for(i=L1.length-1;i>=0;i--){
            //elemento selezionato?
            if(L1.options[i].selected){
               //lo si aggiunge a L2
              L2.options[L2.length]=new Option(L1.options[i].text);
              //lo si elimina da L1
              L1.options[i]=null;
            }//se
          }//per i
        }//if ! semplice
      }//trasferimento
   </script>
  </head>

  <body bgcolor="#C0C0C0">
    <center>
     <h2>Les listes en Javascript</h2>
    <hr>
    <form name="frmListes">
      <table>
        <tr>
          <td>
            <input type="button" name="cmdAjouter" value="Ajouter" onclick="ajouter(lst1A,lst1B,txtElement)">
          </td>
          <td>
            <input type="text" name="txtElement">
          </td>
        </tr>
      </table>
      <table>
        <tr>
          <td align="center">liste 1</td>
          <td align="center"><input type="button" value=">>" onclick="transfert(lst1A,lst2A,true)"</td>
          <td align="center"><input type="button" value="<<" onclick="transfert(lst2A,lst1A,true)"</td>
          <td align="center">liste 2</td>
          <td width="30"></td>
          <td align="center">liste 1</td>
          <td align="center"><input type="button" value=">>" onclick="transfert(lst1B,lst2B,false)"</td>
          <td align="center"><input type="button" value="<<" onclick="transfert(lst2B,lst1B,false)"</td>
          <td align="center">liste 2</td>
        </tr>
         <tr>
          <td></td>
          <td align="center">
            <select name="lst1A" size="5">
            </select>
          </td>
          <td align="center">
            <select name="lst2A" size="5">
            </select>
          </td>
          <td></td>
          <td></td>
          <td></td>
          <td align="center">
            <select name="lst1B" size="5" multiple >
            </select>
          </td>
          <td align="center">
            <select name="lst2B" size="5" multiple>
            </select>
          </td>

        </tr>
        <tr>
          <td></td>
          <td align="center"><input type="button" value="Vider" onclick="vider(lst1A)"</td>
          <td align="center"><input type="button" value="Vider" onclick="vider(lst2A)"</td>
          <td></td>
          <td></td>
          <td></td>
          <td align="center"><input type="button" value="Vider" onclick="vider(lst1B)"</td>
          <td align="center"><input type="button" value="Vider" onclick="vider(lst2B)"</td>
          <td></td>
        </tr>
        <tr>
          <td></td>
          <td colspan="2"><strong>Sélection simple</strong></td>
          <td></td>
          <td></td>
          <td></td>
          <td colspan="2"><strong>Sélection multiple</strong></td>
          <td></td>
        </tr>

      </table>
      <hr>
    </form>
  </body>
</html>