8. Anexos
8.1. Ferramentas de desenvolvimento web
Indicamos aqui onde encontrar e como instalar as ferramentas necessárias para o desenvolvimento web. Algumas ferramentas tiveram as suas versões atualizadas e é possível que as explicações aqui fornecidas já não sejam adequadas para as versões mais recentes. O leitor terá, então, de se adaptar... No curso de programação web, utilizaremos essencialmente as seguintes ferramentas, todas disponíveis gratuitamente:
- um navegador recente capaz de visualizar XML. Os exemplos do curso foram testados com o Internet Explorer 6.
- um JDK (Java Development Kit) recente. Os exemplos do curso foram testados com o JDK 1.4. Este JDK inclui o plug-in Java 1.4 para navegadores, o que permite a estes exibir applets Java que utilizam o Java 1.4.
- Um ambiente de desenvolvimento Java para escrever servlets Java. Neste caso, trata-se do JBuilder 7.
- servidores web: Apache, PWS (Personal Web Server), Tomcat.
- O Apache será utilizado para o desenvolvimento de aplicações web em PERL (Practical Extracting and Reporting Language) ou PHP (Personal Home Page)
- O PWS será utilizado para o desenvolvimento de aplicações web em ASP (Active Server Pages) ou PHP
- O Tomcat será utilizado para o desenvolvimento de aplicações web utilizando servlets Java ou páginas JSP (Java Server Pages)
- uma aplicação de gestão de bases de dados: MySQL
- EasyPHP: uma ferramenta que integra o servidor Web Apache, a linguagem PHP e o SGBD MySQL
8.1.1. Servidores Web, Navegadores, Linguagens de script
- Principais servidores Web
- Apache (Linux, Windows)
- Interner Information Server IIS (NT), Personal Web Server PWS (Windows 9x)
- Principais navegadores
- Internet Explorer (Windows)
- Netscape (Linux, Windows)
- Linguagens de script do lado do servidor
- VBScript (IIS, PWS)
- JavaScript (IIS, PWS)
- Perl (Apache, IIS, PWS)
- PHP (Apache, IIS, PWS)
- Java (Apache, Tomcat)
- Linguagens .NET
- Linguagens de script do lado do navegador
- VBScript (IE)
- JavaScript (IE, Netscape)
- PerlScript (IE)
- Java (IE, Netscape)
8.1.2. Onde encontrar as ferramentas
http://www.netscape.com/ (ligação para downloads) | |
http://www.microsoft.com/windows/ie/default.asp | |
http://www.php.net http://www.php.net/downloads.php (Binários do Windows) | |
http://www.activestate.com http://www.activestate.com/Products/ http://www.activestate.com/Products/ActivePerl/ | |
http://msdn.microsoft.com/scripting (siga o link do script do Windows) | |
http://java.sun.com/ http://java.sun.com/downloads.html (JSE) http://java.sun.com/j2se/1.4/download.html | |
http://www.apache.org/ http://www.apache.org/dist/httpd/binaries/win32/ | |
incluído no NT 4.0 Option Pack para Windows 95 incluído no CD do Windows 98 http://www.microsoft.com/ntserver/nts/downloads/recommended/NT4OptPk/win95.asp | |
http://www.microsoft.com | |
http://jakarta.apache.org/tomcat/ | |
http://www.borland.com/jbuilder/ http://www.borland.com/products/downloads/download_jbuilder.html | |
http://www.easyphp.org/ http://www.easyphp.org/telechargements.php3 |
8.1.3. EasyPHP
Esta aplicação é muito prática, pois reúne num único pacote:
- o servidor Web Apache (1.3.x)
- a linguagem PHP (4.x)
- o SGBD MySQL (3.23.x)
- uma ferramenta de administração do MySQL: PhpMyAdmin
A aplicação de instalação apresenta-se da seguinte forma:

A instalação do EasyPHP decorre sem problemas e é criada uma estrutura de pastas no sistema de ficheiros:

o executável da aplicação | |
a estrutura de diretórios do servidor Apache | |
a estrutura de diretórios do MySQL SGBD | |
a estrutura de diretórios da aplicação phpMyAdmin | |
a estrutura de diretórios do php | |
Raiz da estrutura das páginas web servidas pelo servidor Apache de EasyPHP | |
árvore de diretórios onde é possível colocar os scripts CGI para o servidor Apache |
A principal vantagem do EasyPHP é que a aplicação vem pré-configurada. Assim, o Apache, o PHP e o MySQL já estão configurados para funcionar em conjunto. Quando se inicia o EasyPhp através do seu atalho no menu de programas, aparece um ícone no canto inferior direito do ecrã.
![]() |
É o «E» com um ponto vermelho que deve piscar se o servidor web Apache e a base de dados MySQL estiverem operacionais. Ao clicar nele com o botão direito do rato, acede-se às opções do menu:

A opção Administration permite efetuar ajustes e testes de funcionamento:

8.1.3.1. Administração PHP
O botão «Informações PHP» deve permitir-lhe verificar o bom funcionamento da combinação Apache-PHP: deverá aparecer uma página de informações PHP:

O botão «Extensões» apresenta a lista das extensões instaladas para o PHP. Trata-se, na verdade, de bibliotecas de funções.

O ecrã acima mostra, por exemplo, que as funções necessárias para utilizar a base de dados MySQL estão efetivamente presentes.
O botão «Parâmetros» apresenta o login/motdepasse do administrador da base de dados MySQL.

A utilização da base de dados MySQL excede o âmbito desta breve apresentação, mas fica aqui claro que seria necessário definir uma palavra-passe para o administrador da base de dados.
8.1.3.2. Administração do Apache
Ainda na página de administração do EasyPHP, o link «os seus aliases» permite definir aliases associados a um diretório. Isto permite colocar páginas Web noutros locais que não o diretório www da árvore de diretórios do easyPhp.

Se, na página acima, introduzirmos as seguintes informações:

e utilizarmos o botão valider, as seguintes linhas são adicionadas ao ficheiro <easyphp>\apache\conf\httpd.conf:
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 o diretório de instalação do EasyPHP. httpd.conf é o ficheiro de configuração do servidor Apache. Por isso, é possível fazer o mesmo editando diretamente este ficheiro. Normalmente, uma alteração no ficheiro httpd.conf é imediatamente aplicada pelo Apache. Se tal não acontecer, será necessário parar o servidor e reiniciá-lo, sempre através do ícone do easyphp:

Para concluir o nosso exemplo, podemos agora colocar páginas web na estrutura de diretórios e:\data\serge\web:
e aceder a esta página utilizando o alias st:

Neste exemplo, o servidor Apache foi configurado para funcionar na porta 81. A sua porta predefinida é a 80. Este aspeto é controlado pela seguinte linha do ficheiro httpd.conf, já mencionado anteriormente:
8.1.3.3. O ficheiro de configuração do Apache htpd.conf
Quando se pretende configurar o Apache de forma mais detalhada, é necessário alterar «manualmente» o seu ficheiro de configuração httpd.conf, localizado aqui na pasta <easyphp>\apache\conf:

Eis alguns pontos a reter deste ficheiro de configuração:
função | |
indica a pasta onde se encontra a estrutura de diretórios do Apache | |
indica em que porta o servidor Web irá funcionar. Normalmente, é a 80. Ao alterar esta linha, é possível fazer com que o servidor Web funcione noutra porta | |
o endereço de e-mail do administrador do servidor Apache | |
o nome do computador em que o servidor Apache está a «funcionar» | |
o diretório de instalação do servidor Apache. Quando, no ficheiro de configuração, aparecem nomes relativos de ficheiros, estes são relativos a esta pasta. | |
a pasta raiz da árvore de páginas Web servidas pelo servidor. Aqui, o URL http://machine/rep1/fic1.html corresponderá ao ficheiro E:\Program Files\EasyPHP\www\rep1\fic1.html | |
define as propriedades da pasta anterior | |
pasta dos registos, ou seja, na verdade <ServerRoot>\logs\error.log: E:\Program Files\EasyPHP\apache\logs\error.log. Este é o ficheiro que deve consultar se verificar que o servidor Apache não está a funcionar. | |
E:\Program Files\EasyPHP\cgi-bin será a raiz da árvore de diretórios onde se poderão colocar os scripts CGI. Assim, o URL http://machine/cgi-bin/rep1/script1.pl será o URL do script CGI E:\Program Files\EasyPHP\cgi-bin\rep1\script1.pl. | |
define as propriedades da pasta acima | |
linhas de carregamento dos módulos que permitem ao Apache funcionar com o PHP4. | |
define os sufixos dos ficheiros a considerar como ficheiros a serem processados pelo PHP |
8.1.3.4. Administração do MySQL com o PhpMyAdmin
Na página de administração do EasyPhp, clique no botão PhpMyAdmin:

A lista suspensa em Accueil permite visualizar as bases de bases de dados atuais. | ![]() |
O número entre parênteses corresponde ao número de tabelas. Se escolhermos uma base de dados, as tabelas dessa base são apresentadas: | ![]() |
A página Web oferece várias operações que podem ser realizadas na base de dados:

Se clicarmos na ligação Afficher de user:

Aqui existe apenas um utilizador: root, que é o administrador de MySQL. Ao seguir o link Modifier, seria possível alterar a sua palavra-passe, que atualmente está em branco, o que não é aconselhável para um administrador.
Não nos alongaremos mais sobre o PhpMyAdmin, que é um software abrangente e que mereceria uma descrição de várias páginas.
8.1.4. PHP
Vimos como obter o PHP através da aplicação EasyPhp. Para obter o PHP diretamente, aceda ao site http://www.php.net.
O PHP não se limita apenas à Web. Pode ser utilizado como linguagem de script no Windows. Crie o seguinte script e guarde-o com o nome date.php:
<?
// script PHP que exibe a hora
$maintenant=date("j/m/y, H:i:s",time());
echo "Nous sommes le $maintenant";
?>
Numa janela DOS, aceda ao diretório de date.php e execute-o:
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
É preferível que o Internet Explorer já esteja instalado. Se estiver presente, o Active Perl irá configurá-lo para que aceite scripts PERL nas páginas HTML, scripts esses que serão executados pelo próprio IE no lado do cliente. O site do Active Perl encontra-se em URL http://www.activestate.comA. Após a instalação, o PERL será instalado num diretório a que chamaremos <perl>. Este contém a seguinte estrutura de diretórios:
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
O executável perl.exe encontra-se em <perl>\bin. O Perl é uma linguagem de script que funciona no Windows e no Unix. É também utilizada na programação do WEB. Vamos escrever um primeiro script:
# script PERL que exibe a hora
# módulos
use strict;
# programa
my ($secondes,$minutes,$heure)=localtime(time);
print "Il est $heure:$minutes:$secondes\n";
Guarde este script num ficheiro com o nome heure.pl. Abra uma janela DOS, aceda ao diretório do script anterior e execute-o:
8.1.6. VBScript, JavaScript, PerlScript
Estas linguagens são linguagens de script para o Windows. Podem funcionar em diferentes ambientes, tais como
- o Windows Scripting Host, para utilização direta no Windows, nomeadamente para escrever scripts de administração do sistema
- Internet Explorer. É então utilizado em páginas HTML, às quais confere uma certa interatividade impossível de alcançar apenas com a linguagem HTML.
- Internet Information Server (IIS), o servidor Web da Microsoft no NT/2000, e o seu equivalente, o Personal Web Server (PWS), no Win9x. Neste caso, o VBScript é utilizado para a programação do lado do servidor Web, tecnologia denominada ASP (Active Server Pages) pela Microsoft.
O ficheiro de instalação pode ser obtido no URL: http://msdn.microsoft.com/scripting e deve seguir-se as ligações do Windows Script. São instalados:
- o contêiner Windows Scripting Host, que permite a utilização de várias linguagens de script, tais como VBScript e JavaScript, mas também outras, como o PerlScript, que vem incluído no Active Perl.
- um interpretador VBscript
- um interpretador de JavaScript
Vamos apresentar alguns testes rápidos. Vamos criar o seguinte programa vbscript:
' uma classe
class personne
Dim nom
Dim age
End class
' criação de um objeto «pessoa»
Set p1=new personne
With p1
.nom="dupont"
.age=18
End With
' exibição das propriedades da pessoa p1
With p1
wscript.echo "nom=" & .nom
wscript.echo "age=" & .age
End With
Este programa utiliza objetos. Vamos chamá-lo de objets.vbs (o sufixo vbs indica um ficheiro VBScript). Vamos para o diretório onde ele se encontra e executemo-lo:
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
Vamos agora criar o seguinte programa em JavaScript que utiliza matrizes:
// tabela numa variante
// matriz vazia
tableau=new Array();
affiche(tableau);
// matriz que cresce dinamicamente
for(i=0;i<3;i++){
tableau.push(i*10);
}
// exibição da tabela
affiche(tableau);
// novamente
for(i=3;i<6;i++){
tableau.push(i*10);
}
affiche(tableau);
// tabelas multidimensionais
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);
// fim
WScript.quit(0);
// ---------------------------------------------------------
function affiche(tableau){
// exibição da tabela
for(i=0;i<tableau.length;i++){
WScript.echo("tableau[" + i + "]=" + tableau[i]);
}//para
}//função
// ---------------------------------------------------------
function affiche2(tableau){
// visualização da tabela
for(i=0;i<tableau.length;i++){
for(j=0;j<tableau[i].length;j++){
WScript.echo("tableau[" + i + "," + j + "]=" + tableau[i][j]);
}// para j
}//para i
}//função
Este programa utiliza tabelas. Vamos chamá-lo de tableaux.js (o sufixo «js» indica um ficheiro JavaScript). Vamos para o diretório onde ele se encontra e executemo-lo:
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
Um último exemplo em Perlscript para terminar. É necessário ter o Active Perl instalado para ter acesso ao Perlscript.
<job id="PERL1">
<script language="PerlScript">
# do Perl clássico
%dico=("maurice"=>"juliette","philippe"=>"marianne");
@cles= keys %dico;
for ($i=0;$i<=$#chaves;$i++){
$cle=$cles[$i];
$valeur=$dico{$cle};
$WScript->echo ("clé=".$cle.", valeur=".$valeur);
}
# do PerlScript utilizando objetos do 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>
Este programa demonstra a criação e a utilização de dois dicionários: um no estilo clássico do Perl e outro com o objeto Scripting Dictionary do Windows Script. Vamos guardar este código no ficheiro dico.wsf (wsf é a extensão dos ficheiros do Windows Script). Vamos para a pasta deste programa e executá-lo:
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
O Perlscript pode utilizar os objetos do contentor no qual é executado. Neste caso, tratava-se de objetos do contentor Windows Script. No contexto da programação Web, os scripts VBscript, JavaScript e Perlscript podem ser executados quer no navegador IE, quer num servidor PWS ou IIS. Se o script for um pouco complexo, pode ser aconselhável testá-lo fora do contexto da Web, no contêiner do Windows Script, tal como foi visto anteriormente. Desta forma, só será possível testar as funções do script que não utilizem objetos específicos do navegador ou do servidor. Mesmo com esta restrição, esta possibilidade continua a ser interessante, pois, em geral, é bastante pouco prático depurar scripts que se executam em servidores Web ou navegadores.
8.1.7. JAVA
O Java está disponível no URL: http://www.sun.com e instala-se numa estrutura de diretórios a que chamaremos <java>, que contém os seguintes elementos:
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
Na pasta «bin», encontrar-se-á o javac.exe, o compilador Java, e o java.exe, a máquina virtual Java. Poderão ser realizados os seguintes testes:
- Escrever o seguinte script:
//programa Java que exibe a hora
import java.io.*;
import java.util.*;
public class heure{
public static void main(String arg[]){
// recuperar data e hora
Date maintenant=new Date();
// exibe
System.out.println("Il est "+maintenant.getHours()+
":"+maintenant.getMinutes()+":"+maintenant.getSeconds());
}//main
}//classe
- Guarde este programa com o nome heure.java. Abra uma janela DOS. Navegue até ao diretório do ficheiro heure.java e compile-o:
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.
No comando acima, c:\jdk1.3\bin\javac deve ser substituído pelo caminho exato do compilador javac.exe. Deve obter, no mesmo diretório que o heure.java, um ficheiro heure.class, que é o programa que vai agora ser executado pela máquina virtual java.exe.
- Executar o programa:
8.1.8. Servidor Apache
Vimos que era possível obter o servidor Apache através da aplicação EasyPhp. Para o obter diretamente, iremos ao site do Apache: http://www.apache.org. A instalação cria uma estrutura de diretórios onde se encontram todos os ficheiros necessários para o servidor. Vamos chamar a esta pasta «<apache>». Ela contém uma estrutura semelhante à seguinte:
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
pasta dos ficheiros de configuração do Apache | |
pasta dos ficheiros de registo (monitorização) do Apache | |
os executáveis do Apache |
8.1.8.1. Configuration
Na pasta <Apache>\conf, encontram-se os seguintes ficheiros: httpd.conf, srm.conf, access.conf. Nas versões mais recentes do Apache, os três ficheiros foram reunidos no httpd.conf. Já apresentámos os pontos importantes deste ficheiro de configuração. Nos exemplos que se seguem, foi utilizada para os testes a versão do Apache correspondente ao EasyPhp e, consequentemente, o respetivo ficheiro de configuração. Neste ficheiro, DocumentRoot, que designa a raiz da árvore de páginas Web, é e:\program files\easyphp\www.
8.1.8.2. Link PHP - Apache
Para testar, crie o ficheiro intro.php com apenas a seguinte linha:
<? phpinfo() ?>
e coloque-o na raiz das páginas do servidor Apache (DocumentRoot acima). Aceda ao URL em http://localhost/intro.php. Deve aparecer uma lista de informações php:

O seguinte script PHP apresenta a hora. Já o vimos anteriormente:
<?php
// time: número de milissegundos desde 01/01/1970
// «formato de exibição da data e hora»
// d: dia com 2 dígitos
// m: mês com 2 dígitos
// y: ano com 2 dígitos
// H: hora 0,23
// i: minutos
// s: segundos
print "Nous sommes le " . date("d/m/y H:i:s",time());
?>
Colocamos este ficheiro de texto na raiz das páginas do servidor Apache (DocumentRoot) e chamamo-lo date.php. Acedamos, através de um navegador, ao ficheiro URL http://localhost/date.php. Obtemos a seguinte página:

8.1.8.3. Link PERL-APACHE
É criado através de uma linha com o seguinte formato: ScriptAlias /cgi-bin/ "E:/Program Files/EasyPHP/cgi-bin/" no ficheiro <apache>\conf\httpd.conf. A sua sintaxe é ScriptAlias /cgi-bin/ "<cgi-bin>", em que <cgi-bin> é a pasta onde se podem colocar os scripts CGI. A CGI (Common Gateway Interface) é uma norma de comunicação entre o servidor e as aplicações. Um cliente solicita ao servidor Web uma página dinâmica, gerada por um programa. O servidor WEB deve, portanto, solicitar a um programa que gere a página. O CGI define a comunicação entre o servidor e o programa, nomeadamente o modo de transmissão de informações entre estas duas entidades.
Se necessário, altere a linha ScriptAlias /cgi-bin/ "<cgi-bin>" e reinicie o servidor Apache. Em seguida, faça o seguinte teste:
- Escreva o script:
#!c:\perl\bin\perl.exe
# script PERL a apresentar a hora
# módulos
use strict;
# programa
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
;
- Coloque este script em <cgi-bin>\heure.pl, sendo que <cgi-bin> é a pasta que pode receber scripts CGI (ver httpd.conf). A primeira linha #!c:\perl\bin\perl.exe indica o caminho do executável perl.exe. Altere-o, se necessário.
- Inicie o Apache, caso ainda não o tenha feito
- Aceda, através de um navegador, ao ficheiro URL http://localhost/cgi-bin/heure.pl. Obterá a seguinte página:

8.1.9. O servidor PWS
8.1.9.1. Installation
O servidor PWS (Personal Web Server) é uma versão pessoal do servidor IIS (Internet Information Server) da Microsoft. Este último está disponível nos sistemas NT e 2000. Nos computadores com Win9x, o PWS está normalmente disponível com o pacote de instalação do Internet Explorer. No entanto, não é instalado por predefinição. É necessário efetuar uma instalação personalizada do IE e solicitar a instalação do PWS. Este último também está disponível no «NT 4.0 Option Pack for Windows 95».
8.1.9.2. Primeiros testes
A raiz das páginas Web do servidor PWS é unidade:\inetpub\wwwroot, em que unidade é o disco no qual instalou o PWS. Partimos do princípio, daqui em diante, que essa unidade é a D. Assim, o URL http://machine/rep1/page1.html corresponderá ao ficheiro d:\inetpub\wwwroot\rep1\page1.html. O servidor PWS interpreta qualquer ficheiro com a extensão .asp (Active Server Pages) como um script que deve executar para gerar uma página HTML.
O PWS funciona, por predefinição, na porta 80. O servidor web Apache também... Por isso, é necessário parar o Apache para trabalhar com o PWS, caso tenha ambos os servidores. A outra solução consiste em configurar o Apache para que funcione noutra porta. Assim, no ficheiro de configuração do Apache, substitui-se a linha «Port 80» por «Port 81»; o Apache passará a funcionar na porta 81 e poderá ser utilizado em simultâneo com o PWS. Se o PWS tiver sido iniciado e se aceder ao URL http://localhost, obtém-se uma página semelhante à seguinte:

8.1.9.3. Ligação PHP - PWS
- Abaixo encontra-se um ficheiro .reg destinado a alterar o registo. Clique duas vezes neste ficheiro para alterar o registo. Aqui, o dll necessário encontra-se em d:\php4 juntamente com o executável do PHP. Altere, se necessário. Os \ devem ser duplicados no caminho da DLL.
REGEDIT4
[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\w3svc\parameters\Script Map]
".php"="d:\\php4\\php4isapi.dll"
- Reinicie o computador para que a alteração no Registo seja aplicada.
- Crie uma pasta «php» em d:\inetpub\wwwroot, que é a raiz do servidor PWS. Depois de o fazer, ative o PWS e aceda ao separador «Avançado». Selecione o botão «Adicionar» para criar uma pasta virtual:
- Confirme tudo e reinicie o PWS. Coloque no d:\inetpub\wwwroot\php o ficheiro intro.php, que contém apenas a seguinte linha:
- Solicitar ao servidor PWS o ficheiro URL http://localhost/php/intro.php. Deve ser apresentada a lista de informações PHP já exibidas com o Apache.
8.1.10. Tomcat: servlets Java e páginas JSP (Java Server Pages)
O Tomcat é um servidor Web que permite gerar páginas HTML através de servlets (programas Java executados pelo servidor Web) ou páginas JSP (Java Server Pages), páginas que combinam código Java e código HTML. É o equivalente às páginas ASP (Active Server Pages) do servidor IIS/PWS da Microsoft, onde se mistura código VBScript ou JavaScript com código HTML.
8.1.10.1. Installation
O Tomcat está disponível em URL: http://jakarta.apache.org. Descarrega-se um ficheiro .exe de instalação. Ao iniciar este programa, ele começa por indicar qual o JDK que irá utilizar. Com efeito, o Tomcat necessita de um JDK para se instalar e, posteriormente, compilar e executar os servlets Java. Por isso, é necessário que tenha instalado um JDK Java antes de instalar o Tomcat. Recomenda-se a versão mais recente do JD. A instalação irá criar uma estrutura de diretórios <tomcat>:

consiste simplesmente em descompactar este arquivo num diretório. Escolha um diretório cujo caminho contenha apenas nomes sem espaços (por exemplo, não «Program Files»), pois existe um bug no processo de instalação do Tomcat. Escolha, por exemplo, C:\tomcat ou D:\tomcat. Vamos chamar a este diretório <tomcat>. Nele encontrará uma pasta chamada jakarta-tomcat e, dentro desta, a seguinte estrutura de diretórios:
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. Iniciar/Parar o servidor Web Tomcat
O Tomcat é um servidor Web, tal como o Apache ou o PWS. Para o iniciar, existem ligações no menu de programas:
para iniciar o Tomcat | |
para o desligar |
Quando se inicia o Tomcat, é apresentada uma janela do DOS com o seguinte conteúdo:

É possível minimizar esta janela do DOS. Ela permanecerá ativa enquanto o Tomcat estiver em funcionamento. Pode então passar aos primeiros testes. O servidor Web Tomcat funciona na porta 8080. Depois de iniciar o Tomcat, abra um navegador Web e aceda a http://localhost:8080. Deverá ver a seguinte página:

Siga o link «Servlet Examples»:

Clique na ligação Execute de RequestParameters e, em seguida, na ligação de Source. Terá uma primeira ideia do que é um servlet Java. Poderá fazer o mesmo com os links nas páginas JSP.
Para parar o Tomcat, utilize o link «Stop Tomcat» no menu de programas.
8.1.11. JBuilder
O JBuilder é um ambiente de desenvolvimento de aplicações Java. Para criar servlets Java sem interfaces gráficas, não é imprescindível dispor de um ambiente deste tipo. Um editor de texto e um JDK são suficientes. No entanto, o JBuilder oferece algumas vantagens em relação à técnica anterior:
- facilidade de depuração: o compilador assinala as linhas com erros num programa e é fácil localizar essas linhas
- sugestão de código: quando se utiliza um objeto Java, o JBuilder apresenta em linha a lista das suas propriedades e métodos. Isto é muito prático, tendo em conta que a maioria dos objetos Java possui inúmeras propriedades e métodos que são difíceis de memorizar.
O JBuilder pode ser encontrado no site http://www.borland.com/jbuilder. É necessário preencher um formulário para obter o software. É enviada uma chave de ativação por e-mail. Para instalar o JBuilder 7, procedeu-se, por exemplo, da seguinte forma:
- foram obtidos três ficheiros zip: para a aplicação, para a documentação e para os exemplos. Cada um destes ficheiros zip tem um link separado no site do JBuilder.
- Primeiro, instalou-se a aplicação, depois a documentação e, por fim, os exemplos
- Quando se inicia a aplicação pela primeira vez, é solicitada uma chave de ativação: trata-se da chave que lhe foi enviada por e-mail. Na versão 7, esta chave corresponde, na verdade, ao conteúdo completo de um ficheiro de texto que pode ser colocado, por exemplo, na pasta de instalação do JB7. No momento em que a chave for solicitada, deve indicar o ficheiro em questão. Feito isto, a chave não voltará a ser solicitada.
Existem algumas configurações úteis a efetuar se se pretender utilizar o JBuilder para criar servlets Java. Com efeito, a versão denominada «Jbuilder pessoal» é uma versão simplificada que, nomeadamente, não inclui todas as classes necessárias para o desenvolvimento web em Java. É possível fazer com que o JBuilder utilize as bibliotecas de classes fornecidas pelo Tomcat. Para tal, proceda da seguinte forma:
- executar o JBuilder

- ativar a opção Tools/Configure JDKs

Na secção «JDK Settings» acima, normalmente aparece no campo «Name» um JDK 1.3.1. Se tiver uma versão mais recente do JDK, utilize o botão «Change» para indicar o diretório de instalação desta versão. Acima, foi indicado o diretório E:\Program Files\jdk14, onde estava instalado um JDK 1.4. A partir de agora, o JBuilder utilizará este JDK para as suas compilações e execuções. Na secção (Class, Source, Documentation) encontra-se a lista de todas as bibliotecas de classes que serão exploradas pelo JBuilder, neste caso as classes do JDK 1.4. As classes deste último não são suficientes para realizar desenvolvimento web em Java. Para adicionar outras bibliotecas de classes, utiliza-se o botão «Add» e selecionam-se os ficheiros .jar adicionais que se pretende utilizar. Os ficheiros .jar são bibliotecas de classes. O Tomcat 4.x inclui todas as bibliotecas de classes necessárias para o desenvolvimento web. Estas encontram-se em <tomcat>\common\lib, sendo que <tomcat> é o diretório de instalação do Tomcat:

Com o botão «Add», vamos adicionar estas bibliotecas, uma a uma, à lista de bibliotecas exploradas pelo JBuilder:

A partir de agora, é possível compilar programas Java em conformidade com a norma J2EE, nomeadamente os servlets Java. O JBuilder serve apenas para a compilação, sendo a execução posteriormente assegurada pelo Tomcat, de acordo com as modalidades explicadas no curso.
8.2. Código-fonte dos programas
8.2.1. O cliente genérico TCP
Muitos dos serviços criados nos primórdios da Internet funcionam de acordo com o modelo do servidor de eco estudado anteriormente: as trocas cliente-servidor realizam-se através da troca de linhas de texto. Vamos escrever um cliente TCP genérico que será iniciado da seguinte forma: java cltTCPgenerique servidor porta
Este cliente TCP irá ligar-se à porta port do servidor serveur. Feito isto, irá criar duas threads:
- um thread responsável por ler os comandos digitados no teclado e enviá-los para o servidor
- um thread encarregado de ler as respostas do servidor e de as apresentar no ecrã
Porquê duas threads? Cada serviço TCP-IP tem o seu protocolo específico e, por vezes, verificam-se as seguintes situações:
- o cliente tem de enviar várias linhas de texto antes de obter uma resposta
- a resposta de um servidor pode conter várias linhas de texto
Por isso, o ciclo de envio de uma única linha para o servidor — receção de uma única linha enviada pelo servidor — nem sempre é adequado. Vamos, portanto, criar dois ciclos separados:
- um ciclo de leitura dos comandos digitados no teclado para serem enviados ao servidor. O utilizador indicará o fim dos comandos com a palavra-chave fin.
- um ciclo de receção e exibição das respostas do servidor. Este será um ciclo infinito que só será interrompido pelo encerramento do fluxo de rede pelo servidor ou pelo utilizador, que digitará no teclado o comando fin.
Para que estes dois ciclos fiquem separados, precisamos de dois threads independentes. Vejamos um exemplo de execução em que o nosso cliente TCP genérico se liga a um serviço SMTP (SendMail Transfer Protocol). Este serviço é responsável pelo encaminhamento do correio eletrónico aos seus destinatários. Funciona na porta 25 e utiliza um protocolo de comunicação do tipo troca de linhas de texto.
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]
Vamos comentar estas trocas entre cliente e servidor:
- o serviço SMTP envia uma mensagem de boas-vindas quando um cliente se liga a ele:
- alguns serviços dispõem de um comando help que fornece indicações sobre os comandos que podem ser utilizados com o serviço. Neste caso, não é esse o caso. Os comandos SMTP utilizados no exemplo são os seguintes:
- mail from: expéditeur, para indicar o endereço de e-mail do remetente da mensagem
- rcpt to: destinataire, para indicar o endereço de e-mail do destinatário da mensagem. Se houver vários destinatários, o comando rcpt to: é repetido tantas vezes quantas forem necessárias para cada um dos destinatários.
- data, que sinaliza ao servidor SMTP que a mensagem vai ser enviada. Conforme indicado na resposta do servidor, esta consiste numa sequência de linhas terminada por uma linha que contém apenas o caractere ponto. Uma mensagem pode ter cabeçalhos separados do corpo da mensagem por uma linha em branco. No nosso exemplo, colocámos um assunto com a palavra-chave Subject:
- assim que a mensagem for enviada, é possível indicar ao servidor que terminámos com o comando quit. O servidor encerra então a ligação de rede. O thread de leitura pode detetar este evento e parar.
- O utilizador digita então «fin» no teclado para parar também o thread de leitura dos comandos digitados no teclado.
Se verificarmos o e-mail recebido, temos o seguinte (Outlook):

Note-se que o serviço SMTP não consegue detetar se um remetente é válido ou não. Por isso, nunca se pode confiar no campo from de uma mensagem. Neste caso, o remetente machin@univ-angers.fr não existia.
Este cliente TCP genérico permite-nos descobrir o protocolo de comunicação dos serviços da Internet e, a partir daí, criar classes especializadas para os clientes desses serviços. Vamos descobrir o protocolo de comunicação do serviço POP (Post Office Protocol), que permite recuperar os e-mails armazenados num servidor. Funciona na 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]
Os principais comandos são os seguintes:
- user login, onde se introduz o nome de utilizador na máquina que armazena os nossos e-mails
- pass password, onde se introduz a palavra-passe associada ao nome de utilizador anterior
- list, para obter a lista de mensagens com o número e o tamanho em bytes
- retr i, para ler a mensagem n.º i
- quit, para encerrar a sessão.
Vamos agora descobrir o protocolo de comunicação entre um cliente e um servidor Web, que normalmente funciona na 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]
Um cliente Web envia os seus comandos ao servidor de acordo com o seguinte esquema:
Só depois de receber a linha vazia é que o servidor Web responde. No exemplo, utilizámos apenas um comando:
que solicita ao servidor o URL /index.html e indica que está a trabalhar com o protocolo HTTP versão 1.0. A versão mais recente deste protocolo é a 1.1. O exemplo mostra que o servidor respondeu enviando o conteúdo do ficheiro index.html e, em seguida, encerrou a ligação, uma vez que se observa que o thread de leitura das respostas terminou. Antes de enviar o conteúdo do ficheiro index.html, o servidor web enviou uma série de cabeçalhos terminada por uma linha em branco:
<-- 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>
A linha <html> é a primeira linha do ficheiro /index.html. O que precede denomina-se cabeçalhos HTTP (Protocolo de Transferência HyperText). Não vamos detalhar aqui estes cabeçalhos, mas convém lembrar que o nosso cliente genérico permite o acesso aos mesmos, o que pode ser útil para os compreender. A primeira linha, por exemplo:
indica que o servidor Web contactado compreende o protocolo HTTP/1.1 e que encontrou o ficheiro solicitado (200 OK), sendo 200 um código de resposta HTTP. As linhas
indicam ao cliente que irá receber 11251 bytes correspondentes ao texto HTML (HyperText Markup Language) e que, no final da transmissão, a ligação será encerrada.
Temos, portanto, aqui um cliente TCP muito prático. É certo que faz menos do que o programa oficial telnet, mas foi interessante escrevê-lo nós próprios. O programa do cliente TCP genérico é o seguinte:
// pacotes importados
import java.io.*;
import java.net.*;
public class clientTCPgenerique{
// recebe como parâmetro as características de um serviço na forma
// servidor porta
// liga-se ao serviço
// cria um thread para ler os comandos digitados no teclado
// estas serão enviadas para o servidor
// cria um thread para ler as respostas do servidor
// estas serão apresentadas no ecrã
// tudo termina com o comando «fin» digitado no teclado
// variável de instância
private static Socket client;
public static void main(String[] args){
// sintaxe
final String syntaxe="pg serveur port";
// número de argumentos
if(args.length != 2)
erreur(syntaxe,1);
// anota-se o nome do servidor
String serveur=args[0];
// a porta deve ser um número inteiro >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;
// podem ocorrer problemas
try{
// estabelece-se a ligação ao serviço
client=new Socket(serveur,port);
}catch(Exception ex){
// erro
erreur("Impossible de se connecter au service ("+ serveur
+","+port+"), erreur : "+ex.getMessage(),3);
// fim
return;
}//catch
// criam-se os threads de leitura/gravação
new ClientSend(client).start();
new ClientReceive(client).start();
// fim do thread principal
return;
}// main
// exibição de erros
public static void erreur(String msg, int exitCode){
// exibição de erro
System.err.println(msg);
// encerramento com erro
System.exit(exitCode);
}//erro
}//classe
class ClientSend extends Thread {
// classe responsável por ler os comandos digitados no teclado
// e de as enviar para um servidor através de um cliente TCP passado como parâmetro
private Socket client; // o cliente TCP
// construtor
public ClientSend(Socket client){
// onde se indica o cliente TCP
this.client=client;
}//construtor
// método Run da thread
public void run(){
// dados locais
PrintWriter OUT=null; // fluxo de escrita de rede
BufferedReader IN=null; // fluxo do teclado
String commande=null; // comando lido no teclado
// gestão de erros
try{
// criação do fluxo de escrita de rede
OUT=new PrintWriter(client.getOutputStream(),true);
// criação do fluxo de entrada do teclado
IN=new BufferedReader(new InputStreamReader(System.in));
// ciclo de introdução e envio de comandos
System.out.println("Commandes : ");
while(true){
// leitura do comando digitado no teclado
commande=IN.readLine().trim();
// Concluído?
if (commande.toLowerCase().equals("fin")) break;
// envio do comando para o servidor
OUT.println(commande);
// próximo comando
}//while
}catch(Exception ex){
// erro
System.err.println("Envoi : L'erreur suivante s'est produite : " + ex.getMessage());
}//catch
// fim - fecham-se os fluxos
try{
OUT.close();client.close();
}catch(Exception ex){}
// sinaliza-se o fim do thread
System.out.println("[Envoi : fin du thread d'envoi des commandes au serveur]");
}//execução
}//classe
class ClientReceive extends Thread{
// classe encarregada de ler as linhas de texto destinadas a um
// cliente TCP passado como parâmetro
private Socket client; // o cliente TCP
// construtor
public ClientReceive(Socket client){
// regista-se o cliente TCP
this.client=client;
}//construtor
// método Run da thread
public void run(){
// dados locais
BufferedReader IN=null; // fluxo de leitura de rede
String réponse=null; // resposta do servidor
// gestão de erros
try{
// criação do fluxo de leitura da rede
IN=new BufferedReader(new InputStreamReader(client.getInputStream()));
// ciclo de leitura das linhas de texto do fluxo IN
while(true){
// leitura do fluxo de rede
réponse=IN.readLine();
// fluxo encerrado?
if(réponse==null) break;
// exibição
System.out.println("<-- "+réponse);
}//enquanto
}catch(Exception ex){
// erro
System.err.println("Réception : L'erreur suivante s'est produite : " + ex.getMessage());
}//catch
// fim - fecham-se os fluxos
try{
IN.close();client.close();
}catch(Exception ex){}
// sinaliza-se o fim do thread
System.out.println("[Réception : fin du thread de lecture des réponses du serveur]");
}//execução
}//classe
8.2.2. O servidor TCP genérico
Agora vamos centrar-nos num servidor
- que exibe no ecrã os comandos enviados pelos seus clientes
- e lhes envia, como resposta, as linhas de texto digitadas no teclado por um utilizador. É, portanto, este último que desempenha a função de servidor.
O programa é iniciado com: java serveurTCPgenerique portEcoute, em que portEcoute é a porta à qual os clientes devem ligar-se. O serviço ao cliente será assegurado por duas threads:
- um thread dedicado exclusivamente à leitura das linhas de texto enviadas pelo cliente
- um thread dedicado exclusivamente à leitura das respostas digitadas pelo utilizador. Este indicará, através do comando «fin», que encerra a ligação com o cliente.
O servidor cria duas threads por cliente. Se houver n clientes, haverá 2n threads ativas ao mesmo tempo. O servidor, por sua vez, nunca se encerra, a não ser que o utilizador prima Ctrl-C no teclado. Vejamos alguns exemplos.
O servidor é iniciado na porta 100 e utiliza-se o cliente genérico para comunicar com ele. A janela do cliente é a seguinte:
E:\data\serge\MSNET\c#\rede\cliente tcp genérico> 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]
As linhas que começam por <-- são as enviadas do servidor para o cliente; as restantes são as enviadas do cliente para o servidor. A janela do servidor é a seguinte:
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]
As linhas que começam por <-- são as enviadas do cliente para o servidor. As linhas N: são as enviadas do servidor para o cliente n.º N. O servidor acima ainda está ativo, embora o cliente 1 já tenha terminado. Inicia-se um segundo cliente para o mesmo servidor:
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]
A janela do servidor fica então assim:
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
Vamos agora simular um servidor web, iniciando o nosso servidor genérico na porta 88:
Dos> java serveurTCPgenerique 88
Serveur générique lancé sur le port 88
Vamos agora abrir um navegador e aceder à página http://localhost:88/exemple.html. O navegador irá então ligar-se à porta 88 da máquina localhost e, em seguida, solicitar a página /exemple.html:

Vejamos agora a janela do nosso servidor:
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
<--
Descobrimos assim os cabeçalhos HTTP enviados pelo navegador. Isto permite-nos descobrir, pouco a pouco, o protocolo HTTP. Num exemplo anterior, tínhamos criado um cliente Web que enviava apenas o comando GET. Isso tinha sido suficiente. Vemos aqui que o navegador envia outras informações ao servidor. O objetivo destas é indicar ao servidor que tipo de cliente tem diante de si. Vemos também que os cabeçalhos HTTP terminam com uma linha em branco.
Vamos elaborar uma resposta para o nosso cliente. O utilizador ao teclado é, neste caso, o verdadeiro servidor e pode elaborar uma resposta manualmente. Recordemos a resposta dada por um servidor Web num exemplo anterior:
<-- 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>
Vamos tentar dar uma resposta semelhante:
...
<-- 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]
As linhas que começam por 2: são enviadas do servidor para o cliente n.º 2. O comando fin encerra a ligação do servidor ao cliente. Limitaram-nos, na nossa resposta, aos seguintes cabeçalhos HTTP:
HTTP/1.1 200 OK
2 : Server: serveur tcp generique
2 : Connection: close
2 : Content-Type: text/html
2 :
Não indicamos o tamanho do ficheiro que vamos enviar (Content-Length), mas limitamo-nos a indicar que vamos encerrar a ligação (Connection: close) após o envio do mesmo. Isso é suficiente para o navegador. Ao verificar que a ligação foi encerrada, o navegador saberá que a resposta do servidor está concluída e exibirá a página HTML que lhe foi enviada. Esta página é a seguinte:
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>
Em seguida, o utilizador encerra a ligação ao cliente digitando o comando fin. O navegador fica então a saber que a resposta do servidor está concluída e pode, assim, apresentá-la:

Se, no exemplo acima, executarmos o comando View/Source para ver o que o navegador recebeu, obtemos:

ou seja, exatamente o que foi enviado a partir do servidor genérico.
O código do servidor TCP genérico é o seguinte:
// pacotes
import java.io.*;
import java.net.*;
public class serveurTCPgenerique{
// programa principal
public static void main (String[] args){
// recebe as solicitações dos clientes na porta de escuta
// cria um thread para ler os pedidos do cliente
// estas serão apresentadas no ecrã
// cria um thread para ler os comandos digitados no teclado
// estas serão enviadas como resposta ao cliente
// tudo termina com o comando «fin» digitado no teclado
final String syntaxe="Syntaxe : pg port";
// variável de instância
// existe algum argumento
if(args.length != 1)
erreur(syntaxe,1);
// a porta deve ser um número inteiro >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);
// criamos o serviço de escuta
ServerSocket ecoute=null;
int nbClients=0; // número de clientes processados
try{
// Cria-se o serviço
ecoute=new ServerSocket(port);
// acompanhamento
System.out.println("Serveur générique lancé sur le port " + port);
// ciclo de atendimento aos clientes
Socket client=null;
while (true){ // ciclo infinito — será interrompido com Ctrl-C
// aguarda um cliente
client=ecoute.accept();
// o serviço é executado em threads separadas
nbClients++;
// são criados os threads de leitura/escrita
new ServeurSend(client,nbClients).start();
new ServeurReceive(client,nbClients).start();
// volta-se a ficar à escuta de pedidos
}// fim do while
}catch(Exception ex){
// é sinalizado o erro
erreur("L'erreur suivante s'est produite : " + ex.getMessage(),3);
}//catch
}// fim de main
// exibição dos erros
public static void erreur(String msg, int exitCode){
// exibição do erro
System.err.println(msg);
// paragem com erro
System.exit(exitCode);
}//erro
}//classe
class ServeurSend extends Thread{
// classe responsável por ler as respostas digitadas no teclado
// e de as enviar a um cliente através de um cliente TCP passado ao construtor
Socket client; // o cliente TCP
int numClient; // n.º do cliente
// construtor
public ServeurSend(Socket client, int numClient){
// regista-se o cliente TCP
this.client=client;
// e o seu n.º
this.numClient=numClient;
}//fabricante
// método Run do thread
public void run(){
// dados locais
PrintWriter OUT=null; // fluxo de escrita na rede
String réponse=null; // resposta lida no teclado
BufferedReader IN=null; // fluxo do teclado
// acompanhamento
System.out.println("Thread de lecture des réponses du serveur au client "+ numClient + " lancé");
// gestão de erros
try{
// criação do fluxo de escrita de rede
OUT=new PrintWriter(client.getOutputStream(),true);
// criação do fluxo do teclado
IN=new BufferedReader(new InputStreamReader(System.in));
// ciclo de introdução e envio de comandos
while(true){
// identificação do cliente
System.out.print("--> " + numClient + " : ");
// leitura da resposta digitada no teclado
réponse=IN.readLine().trim();
// Concluído?
if (réponse.toLowerCase().equals("fin")) break;
// envio da resposta para o servidor
OUT.println(réponse);
// resposta seguinte
}//enquanto
}catch(Exception ex){
// erro
System.err.println("L'erreur suivante s'est produite : " + ex.getMessage());
}//catch
// fim - fecham-se os fluxos
try{
OUT.close();client.close();
}catch(Exception ex){}
// assinala-se o fim do thread
System.out.println("[fin du Thread de lecture des réponses du serveur au client "+ numClient+ "]");
}//execução
}//classe
class ServeurReceive extends Thread{
// classe responsável por ler as linhas de texto enviadas ao servidor
// através de um cliente TCP passado ao construtor
Socket client; // o cliente TCP
int numClient; // n.º do cliente
// construtor
public ServeurReceive(Socket client, int numClient){
// regista-se o cliente TCP
this.client=client;
// e o seu n.º
this.numClient=numClient;
}//fabricante
// método Run do thread
public void run(){
// dados locais
BufferedReader IN=null; // fluxo de leitura de rede
String réponse=null; // resposta do servidor
// acompanhamento
System.out.println("Thread de lecture des demandes du client "+ numClient + " lancé");
// gestão de erros
try{
// criação do fluxo de leitura da rede
IN=new BufferedReader(new InputStreamReader(client.getInputStream()));
// ciclo de leitura das linhas de texto do fluxo IN
while(true){
// leitura do fluxo de rede
réponse=IN.readLine();
// fluxo encerrado?
if(réponse==null) break;
// exibição
System.out.println("<-- "+réponse);
}//while
}catch(Exception ex){
// erro
System.err.println("L'erreur suivante s'est produite : " + ex.getMessage());
}//catch
// fim - fecham-se os fluxos
try{
IN.close();client.close();
}catch(Exception ex){}
// assinala-se o fim do thread
System.out.println("[fin du Thread de lecture des demandes du client "+ numClient+"]");
}//execução
}//classe
8.3. JAVASCRIPT
Nesta secção, apresentamos três exemplos de utilização de JavaScript nas páginas WEB. Centramo-nos na gestão de formulários, mas o JavaScript permite fazer muito mais.
8.3.1. Recuperar as informações de um formulário
O exemplo abaixo mostra como recuperar, no navegador, os dados introduzidos pelo utilizador num formulário. Isto permite, geralmente, efetuar um pré-tratamento antes de os enviar para o servidor.
8.3.1.1. O formulário
Temos um formulário que reúne os componentes mais comuns e um botão «Exibir», que permite visualizar os dados introduzidos pelo utilizador.

8.3.1.2. O código
<html>
<head>
<title>Un formulaire traité par Javascript</title>
<script language="javascript">
function afficher(){
// exibe numa lista as informações do formulário
// primeiro apaga-se
effacerInfos();
// exibe o valor dos # campos
with(document.frmExemple){
// campo oculto
ecrire("champ caché="+cache.value);
// campo de texto simples
ecrire("champ textuel simple="+simple.value);
// campo de texto múltiplo
ecrire("champ textuel multiple="+lignes.value);
// botões de opção
for(i=0;i<radio.length;i++){
texte="radio["+i+"]="+radio[i].value;
if(radio[i].checked) texte+=", coché";
ecrire(texte);
}//para
// caixas de seleção
for(i=0;i<qcm.length;i++){
texte="qcm["+i+"]="+qcm[i].value;
if(qcm[i].checked) texte+=", coché";
ecrire(texte);
}//for
//lista suspensa
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);
}//para
//lista de seleção múltipla
for(i=0;i<lstVoitures.length;i++){
texte="lstVoitures["+i+"]="+lstVoitures.options[i].text;
if(lstVoitures.options[i].selected) texte+=",sélectionné";
ecrire(texte);
}//para
//palavra-passe
ecrire("mot de passe="+passwd.value);
}//com
}//função
function ecrire(texte){
// escreve texto na lista de informações
frmInfos.lstInfos.options[frmInfos.lstInfos.length]=new Option(texte);
}//escrever
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"> </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"> </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> </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> </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. Expressões regulares em JavaScript
No navegador, o JavaScript pode ser utilizado para verificar a validade dos dados introduzidos pelo utilizador antes de os enviar para o servidor. Aqui está um programa de teste destas expressões regulares.
8.3.2.1. A página de teste

8.3.2.2. O código da página
<html>
<head>
<title>Les expressions régulières en Javascript</title>
<script language="javascript">
function afficherInfos(){
with(document.frmRegExp){
// há algo a fazer?
if (! verifier()) return;
// Está tudo bem — apagamos os resultados anteriores
effacerInfos();
// verificação do modelo
modele=new RegExp(txtModele.value);
champs=modele.exec(txtChaine.value);
if(champs==null)
// sem correspondência entre o modelo e a cadeia
ecrireInfos("pas de correspondance");
else{
// correspondência - exibimos os resultados obtidos
ecrireInfos("Il y a correspondance");
for(i=0;i<champs.length;i++)
ecrireInfos("champs["+i+"]=["+champs[i]+"]");
}//caso contrário
}//com
}//função
function ecrireInfos(texte){
// escreve texto na lista de informações
document.frmRegExp.lstInfos.options[document.frmRegExp.lstInfos.length]=new Option(texte);
}//escrever
function effacerInfos(){
frmRegExp.lstInfos.length=0;
}//effacerInfos
function jouer(){
// verifica se o modelo corresponde à cadeia de caracteres do exemplo selecionado
with(document.frmRegExp){
txtModele.value=lstModeles.options[lstModeles.selectedIndex].text
txtChaine.value=lstChaines.options[lstChaines.selectedIndex].text
afficherInfos();
}//com
}//reproduzir
function ajouter(){
//adiciona o teste atual aos exemplos
with(document.frmRegExp){
// há algo a fazer?
if (! verifier()) return;
// adição
lstModeles.options[lstModeles.length]=new Option(txtModele.value);
lstChaines.options[lstChaines.length]=new Option(txtChaine.value);
// limpar entradas
txtModele.value="";
txtChaine.value="";
}//com
}//adicionar
function verifier(){
// verifica se os campos de introdução de dados não estão vazios
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
// está tudo bem
return true;
}//com
}//verificar
</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. Gestão de listas em JavaScript
8.3.3.1. O formulário

8.3.3.2. O código
<html>
<head>
<title>Les listes en Javascript</title>
<script language="javascript">
// adicionar
function ajouter(L1,L2,T){
// adiciona o valor do campo T às listas L1, L2
// há algo a fazer?
champs=/^\s*$/.exec(T.value);
if(champs!=null){
// o campo está vazio
alert("Vous n'avez pas indiqué la valeur à ajouter");
txtElement.focus();
return;
}//if
// adiciona-se o elemento
L1.options[L1.length]=new Option(T.value);
L2.options[L2.length]=new Option(T.value);
T.value="";
}//adicionar
//esvaziar
function vider(L){
// esvazia a lista L
L.length=0;
}//esvaziar
//transferir
function transfert(L1,L2,simple){
//transfere para L2 os elementos selecionados na lista L1
// há algo a fazer?
// índice do elemento selecionado em L1
index1=L1.selectedIndex;
if(index1==-1){
alert("Vous n'avez pas sélectionné d'élément");
return;
}//se
// qual é o modo de seleção dos elementos das listas
if(simple){ // seleção simples
element1=L1.options[index1].text;
//adição em L2
L2.options[L2.length]=new Option(element1);
//eliminação em L1
L1.options[index1]=null;
}//simples
if(! simple){ //seleção múltipla
//percorrer a lista 1 na ordem inversa
for(i=L1.length-1;i>=0;i--){
//elemento selecionado?
if(L1.options[i].selected){
//adiciona-se a L2
L2.options[L2.length]=new Option(L1.options[i].text);
//é removido de L1
L1.options[i]=null;
}//se
}//para i
}//se ! simples
}//transferência
</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>


