Corso di Reti di Calcolatori
UNICAL – Facoltà di Ingegneria – a.a. 2002/2003
Esercitazione sul networking in Java (2a parte)
[email protected]
1
java.net.URL
• URL (String spec)
crea un oggetto URL a partire dalla stringa che lo rappresenta
• URL (String protocol, String host, int port, String file)
crea un URL a partire dai componenti specificati (port = -1 indica l’uso della
porta standard per il protocollo specificato)
• URLConnection openConnection()
restituisce un oggetto URLConnection che gestisce la connessione diretta
alla risorsa
• InputStream openStream()
apre un flusso di input per la lettura dei dati della risorsa
2
Recupero del contenuto di un sito Web
import java.io.*;
import java.net.*;
public class URLTest {
public static void main(String[] args) {
try {
URL url = new URL("http://www.deis.unical.it");
BufferedReader in =
new BufferedReader (new InputStreamReader(url.openStream()));
boolean more = true;
while (more) {
String line = in.readLine();
if (line == null)
more = false;
else
System.out.println(line);
}
} catch (IOException e) { System.out.println("Error"+e); }
}
}
3
java.net.URLConnection (1)
Per ottenere dalla risorsa informazioni aggiuntive e controllarne meglio
l’accesso si usa la classe URLConnection.
In generale per creare una URLConnection si seguono i seguenti passi:
1.Si chiama il metodo openConnection di un oggetto URL:
URLConnection connection = url.openConnection();
2.Si impostano le proprietà usando i metodi:
setDoInput
setDoOutput
setIfModifiedSince
setUseCaches
setAllowUserInteraction
setRequestProperty
3.Si effettua la connessione alla risorsa remota mediante il metodo connect:
connection.connect();
Il metodo connect crea una connessione socket con il server e richiede al
server le informazioni di intestazione.
4
java.net.URLConnection (2)
4.Dopo aver attivato la connessione è possibile richiedere le informazioni di
intestazione. I metodi getHeaderFieldKey e getHeaderField consentono di
accedere a tutti i campi di intestazione. I seguenti metodi interrogano i campi
standard:
getContentType
getContentLength
getContentEncoding
getDate
getExpiration
getLastModified
5.Si accede alla risorsa remota, utilizzando il metodo getInputStream per
ottenere un flusso di input per leggere le informazioni, ed il metodo
getOutputStream per ottenere un flusso di output per inviare informazioni.
5
java.net.URLConnection (3)
• void setDoInput(boolean doInput)
se doInput è true, l’utente può ricevere l’input da questo URLConnection
• void setDoOutput(boolean doOutput)
se doOutput è true, l’utente può ricevere l’output da questo URLConnection
• void setIfModifiedSince(long time)
configura questo URLConnection per recuperare solo i dati che sono stati
modificati dopo la data indicata
• void setUseCaches(boolean useCaches)
se useCaches è true, i dati possono essere recuperati da una cache locale
• void setAllowUserInteraction(boolean allowUserInteraction)
se allowUserInteraction è true, all’utente può essere richiesta una password
• void setRequestProperty(String key, String value)
imposta una proprietà della richiesta
6
java.net.URLConnection (4)
• void connect()
si connette alla risorsa remota e recupera le informazioni di intestazione
• String getContentType()
recupera il tipo di contenuto, per esempio text/plain o image/gif
• int getContentLength()
recupera la lunghezza del contenuto, oppure –1 se il valore è sconosciuto
• String getContentEncoding()
recupera la codifica del contenuto, per esempio gzip
• long getDate()
recupera la data di creazione della risorsa
• long getExpiration()
recupera la data di scadenza della risorsa
• long getLastModified()
recupera la data dell’ultima modifica della risorsa
7
java.net.URLConnection (5)
• String getHeaderFieldKey(int n)
recupera l’n-esima chiave del campo di intestazione
• String getHeaderField(n)
recupera l’n-esimo valore del campo di intestazione
• InputStream getInputStream()
restituisce uno stream per leggere la risorsa
• OutputStream getOutputStream()
restituisce uno stream per scrivere sulla risorsa
8
URLConnectionTest (1)
import java.io.*; import java.net.*; import java.util.*;
public class URLConnectionTest {
public static void main(String[] args) {
try {
URL url = new URL("http://java.sun.com");
URLConnection connection = url.openConnection();
connection.connect();
// print header fields
int n = 1;
String key;
while ((key = connection.getHeaderFieldKey(n)) != null) {
String value = connection.getHeaderField(n);
System.out.println(key + ": " + value);
n++;
}
// print convenience functions
System.out.println("----------");
System.out.println("getContentType: "+connection.getContentType());
9
URLConnectionTest (2)
System.out.println("getContentLength: "+connection.getContentLength());
System.out.println("getContentEncoding: "
+connection.getContentEncoding());
System.out.println("getDate: "+connection.getDate());
System.out.println("getExpiration: "+connection.getExpiration());
System.out.println("getLastModifed: "+connection.getLastModified());
System.out.println("----------");
BufferedReader in = new BufferedReader(new
InputStreamReader(connection.getInputStream()));
// print first ten lines of contents
String line; n = 1;
while ((line = in.readLine()) != null && n <= 10) {
System.out.println(line);
n++;
}
if (line != null) System.out.println(". . .");
} catch (IOException exception) { System.out.println("Error: " + exception); }
}
}
10
URLConnectionTest (3)
L’output del programma è il seguente:
Server: Netscape-Enterprise/6.0
Date: Sat, 12 Oct 2002 23:15:45 GMT
Content-type: text/html
Connection: close
---------getContentType: text/html
getContentLength: -1
getContentEncoding: null
getDate: 1034453745000
getExpiration: 0
getLastModifed: 0
---------<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<HTML>
<HEAD>
<TITLE>The Source for Java(TM) Technology</TITLE>
...
11
Invio di dati ad un server Web (1)
Per inviare informazioni ad un server Web sono disponibili due metodi:
GET e POST
Con il metodo GET i parametri si allegano alla fine dell’indirizzo URL:
http://host/procedura?name1=value1&name2=value2
I parametri sono separati tra loro da una &, e devono essere codificati
secondo la specifica URL nel modo seguente: i caratteri alfanumerici ed i
caratteri - _ . * non vengono modificati, mentre gli spazi vengono sostituiti
dal carattere + e tutti gli altri sono rappresentati nel formato %UV dove 0xUV
è il byte di ordine minore del carattere.
Esiste una classe java.net.URLEncoder che offre due metodi:
• static String encode (String s)
restituisce la forma codificata secondo la specifica URL della stringa s
• static String decode (String s)
restituisce la stringa s decodificata
12
Invio di dati ad un server Web (2)
Con il metodo GET si possono includere solo un numero limitato di caratteri.
Il metodo POST non utilizza parametri, ma recupera un flusso di output da
URLConnection e scrive le coppie nome/valore su questo flusso.
Il processo per inviare dati ad una procedura con POST è il seguente:
// si stabilisce una URLConnection
URL url = new URL (“http://host/procedura”);
URLConnection connection = url.openConnection();
// si prepara la connessione all’output
connection.setDoOutput(true);
// si ottiene un flusso di output e si trasmette la sequenza di dati al server
PrintWriter out = new PrintWriter(connection.getOutputStream());
out.println(name1+”=“+URLEncoder.encode(value1)+”&”);
out.println(name2+”=“+URLEncoder.encode(value2)+”\n”);
out.close();
13
Invio di dati ad un server Web (3)
Quindi la risposta del server viene letta nel solito modo:
BufferedReader in = new BufferedReader
(new InputStreamReader (connection.getInputStream()));
String line;
while ((line = in.readLine()) != null)
{
elabora riga
}
14
PostTest (1)
La pagina Web http://www.census.gov/ipc/www/idbprint.html
contiene un modulo per richiedere dati sulla popolazione dei diversi paesi:
<form method=post action="/cgi-bin/ipc/idbsprd">
…
<select name="tbl" size=8 >
<option value="001">001 Total Midyear Population
<option value="002">002 Urban Population as a Percent of Total Population
…
</select>
</form>
La procedura eseguita quando si preme “invio” è ”/cgi-bin/ipc/idbsprd“, ed è
necessario usare il metodo POST per inviare dati alla procedura.
Il componente dell’interfaccia che consente di scegliere l’opzione desiderata
si chiama “tbl”. Scegliendo l’opzione “001” si ottiene la tabella sulla
popolazione totale a metà anno.
15
PostTest (2)
La pagina consente di impostare altri campi:
“cty”, il cui valore indica il paese di cui si vogliono ottenere i dati
“opyr”, il cui valore indica l’intervallo temporale prescelto (si usa il valore
“latest checked” per ottenere i dati più recenti)
Per recuperare i dati più recenti relativi alla popolazione della Cina si
costruisce la stringa:
tbl=1&cty=CH&optyr=latest+checked
si invia la stringa all’indirizzo URL:
http://www.census.gob/cgi-bin/ipc/idbsprd
quindi si recupera l’output.
Il programma seguente invia i dati via POST ad un URL arbitrario. I dati sono
specificati nel file di proprietà PostTest.properties.
16
PostTest (3)
import java.io.*; import java.net.*; import java.util.*;
public class PostTest {
public static void main(String[] args) {
try {
String fileName = "PostTest.properties";
Properties props = new Properties();
FileInputStream in = new FileInputStream(fileName);
props.load(in);
URL url = new URL(props.getProperty("URL"));
props.remove("URL");
String r = doPost(url, props);
System.out.println(r);
} catch (IOException exception) { System.out.println("Error: " + exception); }
}
public static String doPost(URL url, Properties nameValuePairs)
throws IOException {
URLConnection connection = url.openConnection();
connection.setDoOutput(true);
17
PostTest (4)
PrintWriter out = new PrintWriter(connection.getOutputStream());
Enumeration enum = nameValuePairs.keys();
while (enum.hasMoreElements()) {
String name = (String)enum.nextElement();
String value = nameValuePairs.getProperty(name);
char ch;
if (enum.hasMoreElements())
ch = '&';
else
ch = '\n';
out.print(name + "="+URLEncoder.encode(value) + ch);
}
out.close();
BufferedReader in;
try {
in = new BufferedReader (new
InputStreamReader(connection.getInputStream()));
}
18
PostTest (5)
catch (FileNotFoundException exception) {
InputStream err = ((HttpURLConnection)connection).getErrorStream();
if (err == null) throw exception;
in = new BufferedReader(new InputStreamReader(err));
}
StringBuffer response = new StringBuffer();
String line;
while ((line = in.readLine()) != null)
response.append(line + "\n");
in.close();
return response.toString();
}
}
19
PostTest (6)
Contenuto del file PostTest.properties:
URL=http://www.census.gov/cgi-bin/ipc/idbsprd
tbl=001
cty=CH
optyr=latest checked
20
PostTest (7)
L’output del programma è il seguente:
<PRE>
U.S. Bureau of the Census, International Data Base
Table 001. Total Midyear Population
-------------------------CtYear
Population
--------------------------
CH2002
1279160885
-------------------------Source: U.S. Bureau of the Census, International Data Base.
</PRE>
21
Bibliografia
• Cay S. Horstmann, Gary Cornell
Java 2 Volume II – Tecniche avanzate
Quarta Edizione – McGraw-Hill
Capitolo 3: Comunicazione di Rete
• The Java Tutorial:
http://java.sun.com/docs/books/tutorial/networking
22