La comunicazione tra computer si basa su una serie di protocolli disposti in 7 livelli. Considerando solo i protocolli usati da Java per la comunicazione via Internet possiamo limitarci ai 3 livelli superiori:
Livello | Nome protocolli | Funzione protocolli |
Applicazione | HTTP,ftp,telnet,smtp,ping... | applicazione ad alto livello |
Trasporto | TCP,UDP,... | riassemblaggio pacchetti |
Rete | IP,.. | trasferimento pacchetti |
Ogni protocollo di livello superiore ha bisogno dei livelli inferiori per funzionare.Cosi' su Internet ogni comunicazione avviene basandosi sul cosiddetto protocollo TCP/IP che prevede che ogni nodo ha un suo indirizzo IP numerico. Quando viene inviato ad esempio un mail (livello superiore) questo viene diviso in pacchetti e su ognuno di questi
e' indicato l'indirizzo del destinatario. Ogni pacchetto viene inviato per conto suo e istradato dai router. All'arrivo il messaggio viene ricomposto.
In gergo i pacchetti di IP sono detti datagrams e sono formati da un
header contenente indirizzi di mittente e destinatario e da un data
payload che contiene fino a 65K bytes.Uno speciale programma traceroute
(tracert su PC) permette di seguire il cammino di un pacchetto dal mittente al destinatario. Se si indica il nome del computer invece dell'indirizzo numerico,dei
nodi speciali di Internet, i Domain Name Server provvedono a ricavare il numero corrispondente.
tracert www.yahoo.com Tracing route to www.yahoo.com [204.71.200.74] over a maximum of 30 hops: 1 1 ms 1 ms 1 ms cisco.ba.infn.it [192.135.10.2] 2 2 ms 2 ms 4 ms rc-infnba.ba.garr.net [193.206.137.77] 3 10 ms 7 ms 9 ms na-ba-1.garr.net [193.206.134.121] 4 161 ms 164 ms 162 ms garr-neaples.ny.dante.net [212.1.200.105] 5 158 ms 162 ms 166 ms 500.POS2-2.GW9.NYC4.ALTER.NET [157.130.19.21] 6 160 ms 161 ms * 110.ATM3-0.XR2.NYC4.ALTER.NET [152.63.21.198] 7 162 ms 161 ms 160 ms 188.ATM7-0.XR2.NYC1.ALTER.NET [146.188.178.101] 8 161 ms 166 ms * 194.ATM10-0-0.BR1.NYC1.ALTER.NET [146.188.177.14 9] 9 173 ms 178 ms 181 ms s5-0-1.ar2.JFK.gblx.net [206.132.150.129] 10 183 ms * * pos3-1-155M.cr1.JFK.gblx.net [206.132.253.97] 11 * * 524 ms pos6-0-622M.cr2.SNV.gblx.net [206.132.151.14] 12 443 ms 428 ms 431 ms pos1-0-2488M.hr8.SNV.gblx.net [206.132.254.41] 13 443 ms 441 ms 444 ms 208.178.22.58 14 397 ms 412 ms 426 ms www.yahoo.com [204.71.200.74] Trace complete.Al livello di trasporto abbiamo 2 differenti protocolli TCP(Transmission Control Protocol) e UDP(User Datagram Protocol).Questi protocolli si occupano di riassemblare il messaggio sul computer del destinatario. TCP garantisce il corretto ordine e percio' provvede a farsi ritrasmettere i pacchetti mancanti assicurando quindi una connessione affidabile. Viceversa UDP non garantisce il corretto ordine ne si assicura che tutti i pacchetti siano arrivati. UDP viene usato nei casi in cui la perdita di qualche pacchetto e' accettabile:trasmissioni audio o video. Quasi tutti i protocolli dell'ultimo livello (HTTP,telnet,ftp) usano TCP, solo qualcuno come ping usa UDP.
Con Java potete:
more /etc/services more /etc/inetd.confPer comunicare attraverso una certa frequenza si crea un socket.Nel caso del protocollo TCP si puo' aprire una connessione attraverso un socket e tenerla aperta finche' tutti i dati sono stati trasmessi. Questo permette l'uso con TCP delle normali catene di stream usate per l'I/O dai files.
file EchoClient.java
import java.io.*; import java.net.*; public class EchoClient { public static void main(String[] args) throws IOException { Socket echoSocket = null; PrintWriter out = null; BufferedReader in = null; try { echoSocket = new Socket(args[0], Integer.parseInt(args[1])); out = new PrintWriter(echoSocket.getOutputStream(), true); in = new BufferedReader(new InputStreamReader(echoSocket.getInputStream())); } catch (UnknownHostException e) { System.err.println("Don't know about host: "+args[0]); System.exit(1); } catch (IOException e) { System.err.println("Couldn't get I/O for the connection to: "+args[0]); System.exit(1); } System.out.println("Server welcome is: "+in.readLine()); out.println("Hello how are you"); System.out.println("Server responded: "+in.readLine()); out.println("Some other stuff"); System.out.println("Server now responded: "+in.readLine()); out.close(); in.close(); echoSocket.close(); } }Questo programma presenta lo schema tipico di un client TCP:
socket
verso il computer e la porta del server col quale si vuole comunicare.
file MyServer.java
import java.net.*; import java.io.*; import java.util.*; public class MyServer { public static void main(String[] args) throws IOException { ServerSocket serverSocket = null; try { serverSocket = new ServerSocket(Integer.parseInt(args[0])); } catch (IOException e) { System.err.println("Could not listen on port."); System.exit(1); } while (true) { Socket clientSocket = null; try { System.out.println("Server listnening"); clientSocket = serverSocket.accept(); } catch (IOException e) { System.err.println("Accept failed."); System.exit(1); } PrintWriter out = new PrintWriter(clientSocket.getOutputStream(), true); BufferedReader in = new BufferedReader( new InputStreamReader( clientSocket.getInputStream())); String inputLine, outputLine; out.println("Welcome to the echo server."); while ((inputLine = in.readLine()) != null) { if (inputLine.equals("Bye.")) break; Date now = new Date(System.currentTimeMillis()); out.println(now+": "+inputLine); } out.close(); in.close(); clientSocket.close(); } } }Ed ecco lo schema tipico di un server TCP che si mette in attesa di connessione .
serversocket
sulla porta prestabilita.
accept()
di serversocket.
Questo ritorna un normale socket
se un client
cerca di comunicare.
file DataClient.java
import java.io.*; import java.net.*; import java.util.*; public class DataClient { public static void main(String[] args) throws IOException { // get a datagram socket DatagramSocket socket = new DatagramSocket(); // send request byte[] buf = new byte[256]; String hello = "Hello how re you?"; buf = hello.getBytes(); InetAddress address = InetAddress.getByName(args[0]); DatagramPacket packet = new DatagramPacket(buf, buf.length, address, Integer.parseInt(args[1])); System.out.println("Sending packet to: "+address); socket.send(packet); // get response byte[] rbuf = new byte[256]; packet = new DatagramPacket(rbuf, rbuf.length); socket.receive(packet); // display response String received = new String(packet.getData()); System.out.println("From server : " + received); socket.close(); } }Ed ecco lo schema di un client UDP:
DatagramSocket
InetAddress
e carica l'indirizzo del computer destinatario.
DatagramPacket
file DataServer.java
import java.net.*; import java.util.*; public class DataServer { public static void main(String args[]) { while (true) { try { DatagramSocket socket = new DatagramSocket(Integer.parseInt(args[0])); byte[] inbuf = new byte[256]; // receive request DatagramPacket packet = new DatagramPacket(inbuf, inbuf.length); System.out.println("Waiting to receive packet"); socket.receive(packet); byte[] outbuf = new byte[256]; // figure out response Date now = new Date(System.currentTimeMillis()); String outs = new String(inbuf); outs = now.toString() + " " + outs; System.out.println("Replying to "+packet.getAddress()); outbuf = outs.getBytes(); // send the response to the client at "address" and "port" InetAddress address = packet.getAddress(); int port = packet.getPort(); packet = new DatagramPacket(outbuf, outbuf.length, address, port); socket.send(packet); socket.close(); } catch (Exception e) { e.printStackTrace(); } } } }Il server UDP e' identico al client, solo che qui le operazioni di ricevere e inviare sono scambiate.
file FetchURL.java
import java.net.*; import java.io.*; class FetchURL { public static void main (String[] args) { try { URL cernHome = new URL ("http://www.cern.ch"); URLConnection cernHomeConnection = cernHome.openConnection(); BufferedReader in = new BufferedReader( new InputStreamReader ( cernHomeConnection.getInputStream())); String inputLine; while ( (inputLine=in.readLine())!=null) { System.out.println(inputLine); } in.close(); } catch (MalformedURLException e) { System.out.println("Malformed URL Exception "+e); } catch (IOException e ) { System.out.println("IO Exception "+e); } } }Questo e' un client Web (cioe' http) e lo schema da usare e' il seguente:
URLConnection
aprendo una connessione all'URL
file WriteURL.java
import java.io.*; import java.net.*; public class WriteURL { public static void main(String[] args) throws Exception { if (args.length != 1) { System.err.println("Usage: java Reverse string_to_reverse"); System.exit(1); } String stringToReverse = URLEncoder.encode(args[0]); URL url = new URL("http://java.sun.com/cgi-bin/backwards"); URLConnection connection = url.openConnection(); connection.setDoOutput(true); PrintWriter out = new PrintWriter(connection.getOutputStream()); out.println("string=" + stringToReverse); out.close(); BufferedReader in = new BufferedReader( new InputStreamReader( connection.getInputStream())); String inputLine; while ((inputLine = in.readLine()) != null) System.out.println(inputLine); in.close(); } }Java imita il meccanismo di invio di dati da un modulo col cosiddetto metodo di POST. L'effetto e' lo stesso che se aveste cliccato sul tasto di invio in questo modulo. (Potete provare questo programma con la lavagna elettronica del corso Java/C++ che ha come indirizzo "http://www.ba.infn.it/zitobin/nph-guestchat.pl" inviando la stringa "comment=commento").
file CheckURL.java
import java.net.*; import java.io.*; class CheckURL { static BufferedReader myInput; static FileReader myFile; public static void main (String[] args) { try{ String nomeurl; myFile = new FileReader("list.txt"); myInput = new BufferedReader(myFile); while ( myInput.ready() ){ nomeurl=myInput.readLine(); try { URL theURL = new URL (nomeurl); System.out.println("Testing "+nomeurl); try { URLConnection con= theURL.openConnection(); con.getContent(); String temp=con.getHeaderField(0); System.out.println("Header "+temp); int fileNotFound=temp.indexOf("Not Found"); if ( fileNotFound >=0 ) System.out.println("***********Bad link***************"); }catch(IOException e){ System.out.println("***********Bad link***************"); } } catch (MalformedURLException e) { System.out.println("Malformed URL Exception "+e); } } }catch(Exception e2){} } }Questo programma va fatto girare con :
java -Dsun.net.client.defaultReadTimeout=60000 -Dsun.net.client.defaultConnectTimeout=60000 CheckURLper evitare che rimanga in attesa senza fine su qualcuno degli indirizzi. Qui trovate un spiegazione piu' dettagliata sul controllo degli indirizzi Web.
Applicazione 5: Scrivete un server Web.S
file TinyHttpd.java
// From Exploring Java, 2nd.Ed., by P. Niemeyer & J. Peck, O'Reilly Pub. import java.net.*; import java.io.*; import java.util.*; public class TinyHttpd { public static void main( String argv[] ) throws IOException { // Get the port number from the command line. // Create a ServerSocket object to watch that port for clients ServerSocket ss = new ServerSocket( Integer.parseInt(argv[0]) ); System.out.println("starting..."); // Here we loop indefinitely, just waiting for clients to connect while ( true ) { // accept() does not return until a client requests a connection // Now that a client has arrived, create an instance of our special // thread subclass to respond to it. new TinyHttpdConnection( ss.accept() ).start(); System.out.println("new connection"); } // Now loop back around and wait for next client to be accepted. } } class TinyHttpdConnection extends Thread { Socket client; // Pass the socket as a argument to the constructor TinyHttpdConnection ( Socket client ) throws SocketException { this.client = client; // Set the thread priority down so that the ServerSocket // will be responsive to new clients. setPriority( NORM_PRIORITY - 1 ); } public void run() { try { // Use the client socket to obtain an input stream from it. // For text input we wrap an InputStreamReader around // the raw input stream and set ASCII character encoding. // Finally, use a BufferReader wrapper to obtain // buffering and higher order read methods. BufferedReader in = new BufferedReader( new InputStreamReader(client.getInputStream(), "8859_1") ); // Now get an output stream to the client. OutputStream out = client.getOutputStream(); // For text output we wrap an OutputStreamWriter around // the raw output stream and set ASCII character encoding. // Finally, we use a PrintWriter wrapper to obtain its // higher level output methods. // Open in append mode. PrintWriter pout = new PrintWriter( new OutputStreamWriter(out, "8859_1"), true ); // First read the request line from the client String request = in.readLine(); System.out.println( "Request: "+request ); // Check if HTTP/1.0 or later. If so, add MIME header boolean sendMIME = false; if ( request.indexOf("HTTP/") != -1) sendMIME = true; // Use aStringTokenizer to examine the request text. StringTokenizer st = new StringTokenizer( request ); // Check that the request has a minimun number of words // and that the first word is the GET command. if ( (st.countTokens() >= 2) && st.nextToken().equals("GET") ) { // Ignore the leading "/" on the file name. if ( (request = st.nextToken()).startsWith("/") ) request = request.substring( 1 ); // If no file name is there, use index.html default. if ( request.endsWith("/") || request.equals("") ) request = request + "index.html"; // Check if the file is hypertext or plain text String ContentType; if (request.endsWith(".html") || request.endsWith(".htm")) { ContentType = "text/html"; } else { ContentType = "text/plain"; } // Now read the file from the disk and write it to the // output stream to the client. try { // Open a stream to the file. Remember that by this // all the text but the file name has been stripped // from the "request" string. FileInputStream fis = new FileInputStream ( request ); if( sendMIME) { // Follow example in "Java Network Programming", chp.8 PrintStream os = new PrintStream(out); os.print("HTTP/1.0 200 OK\r\n"); Date now = new Date(); os.print("Date: " + now + "\r\n"); os.print("Server: TinyHttpd 1.0\r\n"); os.print("Content-length: " + fis.available() + "\r\n"); os.print("Content-type: " + ContentType + "\r\n\r\n"); } // Creat a byte array to hold the file. byte [] data = new byte [ fis.available() ]; fis.read( data ); // Read file into the byte array out.write( data ); // Write it to client output stream out.flush(); // Remember to flush output buffer fis.close(); } catch ( FileNotFoundException e ) { // If no such file, then send the famous 404 message. pout.println( "404 Object Not Found" ); } } else pout.println( "400 Bad Request" ); client.close(); } catch ( IOException e ) { System.out.println( "I/O error " + e ); } // On return from run() the thread process will stop. } }
GET /index.html HTTP 1.0inviando il file richiesto Questo server e' scritto pero' in modo da poter rispondere a piu' richieste contemporaneamente. Per far questo, crea un nuovo Thread per ogni richiesta. L'oggetto Thread provvede a creare il socket per comunicare col cliente, a creare la catena di stream e ad inviare il file attraverso di essa.Quando l'invio del file e' terminato, il socket viene chiuso e il Thread termina l'esecuzione.
Applicazione 6: Scrivete un'applicazione che si collega alla porta 37 per mostrare la data su un computer remoto .S
file DateAtHost.java
import java.net.*; import java.io.*; public class DateAtHost extends java.util.Date { static int timePort = 37; static final long offset = 2208988800L; // Seconds from century to // Jan 1, 1970 00:00 GMT public DateAtHost( String host ) throws IOException { this( host, timePort ); } public DateAtHost( String host, int port ) throws IOException { Socket sock = new Socket( host, port ); DataInputStream din = new DataInputStream(sock.getInputStream() ); int time = din.readInt(); sock.close(); setTime( (((1L << 32) + time) - offset) * 1000 ) ; } // Example usage: java DateAtHost helio.ora.com public static void main (String [] args) { try { System.out.println( new DateAtHost( args[0] ) ); } catch (UnknownHostException e){ System.out.println("Host " + args[0] +" is unknown."); } catch (IOException e){ System.out.println("IO Exception"); } } }Qui abbiamo un Client TCP che si collega alla porta 37 di un computer remoto. Se questo ha un servizio di data funzionante, il programma riceve il suo valore che viene stampato. Ad esempio :
java DateAtHost helio.ora.com Wed Feb 23 20:13:50 GMT+03:30 2000(Per trovare dei server che danno il tempo , cerca "time server 37").
Anche il programma di simulazione alla base del corso, si basa su un server TCP che e' in attesa di richieste da parte di client, e ad ogni richiesta invia il risultato dell ultime misure effettuate.
Applicazione 7: Scrivete un'applicazione che simula un'esperimento per il calcolo della costante di gravita' g.L'applicazione ha un'interfaccia grafica che permette di pilotare e seguire la simulazione in corso. Essa e' al tempo stesso un server TPC che puo' inviare gli ultimi dati simulati a un client che ne faccia richiesta.Il client e' un applet che permette di collegarsi al server e di mostrare i dati ricevuti.S
![]() | Questa e' l'applicazione che fa da server dei dati sperimentali.Si tratta di un frame che contiene un applet. Quest'ultimo, oltre ad altri oggetti grafici, contiene una canvas e un panel. Nella canvas a sinistra viene mostrata la simulazione dell'esperimento, nel panel a destra un istogramma delle misure fatte.Altri oggetti grafici usati sono il cerchio colorato in rosso e lo stesso istogramma. |
![]() | L'applet oltre ad avere finestre per dare il nome del computer e l'username, ha una textarea per mostrare lo stato della connessione. Quindi 2 istogrammi che rappresentano i dati in arrivo. |
java -cp Esperimento.jar DataMonitor.DataServere la chiamata all'applet client va fatta qui.
javac -d ./ DataMonitor/*.java FOExperiment/*.java ThirdParty/BarChart/*.java.Possono anche venir compresse (zippate) in un'unico file che rispetti questa struttura.Questi files Java archive(.jar) sono la maniera migliore di distribuire i programmi Java.
jar -cvf Esperimento.jar DataMonitor/*.class FOExperiment/*.class ThirdParty/BarChart/*.classe la chiamata all'applet client va modificata nel seguente modo:
<applet code=DataMonitor.DataClient.class archive=Esperimento.jar width=600 height=500></applet>
Ecco la struttura dei pacchetti:
DataChart
per realizzare l'istogramma.
BarChart
deve rappresentare
BoxShoot
, a destra il Panel G_Detector
,oltre
che una serie di TextField sotto.
Histogram
usato per visualizzare gli ultimi
dati generati.Contiene anche il thread che genera i dati.
Circle
per realizzare il cerchio rosso.
objectToDraw
e rappresenta il cerchio rosso.
Histogram
e un DataChart
. Crea un oggetto
DataReader
che gestisce il colloquio col server.
FallingObject
. Contiene anche il codice
per realizzare il server dell'esperimento.Crea per ogni richiesta un oggetto
DataSender
.
DataChart
che a sua
volta usa BarChart
.
Histogram
per costruire l'istogramma.