Programmation réseau en Java

Suite de protocoles TCP/IP

Paquetage java.net

Identification d'une machine

La classe InetAddress - Internet adresses (numérique IP adresses et nomes de hosts )

La classe URL

Serveurs et clients

4.1 Suite de protocoles TCP/IP

Des exemples de protocoles des couches de transport et d'application (Image copiée de ce site )

IP (Internet protocol) - commutation par paquets(datagrames). Pas d'API  Java standard permettant la manipulation directe de protocole IP

UDP (User Datagram Protocol) - la transmission par message, rapide, non fiable, en mode non connecté

TCP (Transmission Control Protocol) - transmission par flot, fiable, moins rapide en mode connecté

 4.2 Paquetage java.net

Ce paquetage fournit un ensemble de classes pour communiquer sur le réseau Internet (et Intranet), télécharger des URL, définir des nouveaux protocoles

Il permet notamment de créer et d'accéder à

Interfaces Classes Exceptions
ContentHandlerFactory
FileNameMap
SocketImplFactory
SocketOptions
URLStreamHandlerFactory
Authenticator
ContentHandler
DatagramPacket
DatagramSocket
    MulticastSocket
DatagramSocketImpl
InetAddress
NetPermission
PasswordAuthentication
ServerSocket
Socket
SocketImpl
SocketPermission
URL
URLClassLoader
URLConnection
    HttpURLConnection
    JarURLConnection
URLDecoder
URLEncoder
URLStreamHandler
MalformedURLException
ProtocolException
SocketException
    BindException
    ConnectException
    NoRouteToHostException
UnknownHostException
UnknownServiceException

  4.3 Identification d'une machine (carte d'interface réseau)

Adresse IP  - DNS forme - refg.tu-sofia.bg
                      “dotted quad”  forme - 194.141.64.254

32 bits en IPv4:   

0xxx: il s'agit d'une adresse de classe A
10xx: il s'agit d'une adresse de classe B
110xx: il s'agit d'une adresse de classe C

128 bits en IPv6

 

  4.4 La classe InetAddress - Internet addresses (numeric IP addresses et host names)


Ne possède pas des variables et constructeurs publiques

Quelques fonctions:

static InetAddress getByName(String host) -  Détermine  l'adresse IP d'une machine (host).
static InetAddress[] getAllByName(String host) - Détermine tous les adresses IP d'une machine.
public static InetAddress getByAddress(byte[] addr) - IPv4 doit être 4 octets, IPv6 - 16.
static InetAddress getLocalHost() - l'adresse de la machine locale.
                      getByName(null) ~ getByName("localhost") ~  getByName("127.0.0.1")

 String getHostAddress() - l' adresse  IP comme une chaîne "%d.%d.%d.%d".
 String getHostName() -   nom de la machine à cette adresse.
 boolean isMulticastAddress() -  vérifie s'il sois une  multicast IP addresse.
 
import java.net.*; 
public class NSLookupApp {
   public static void main(String args[]) {
      try {
            if(args.length!=1){ 
               System.out.println("Usage: java NSLookupApp hostName"); 
               return; 
           }
            InetAddress host = InetAddress.getByName(args[0]);
            String hostName = host.getHostName(); 
            System.out.println("Host name: "+hostName); 
           System.out.println("IP address: "+host.getHostAddress()); 
      }
      catch(UnknownHostException ex) { 
            System.out.println("Unknown host");
            return; 
      }
   }
}
java NSLookupApp localhost
Host name: localhost 
IP address: 127.0.0.1 

Exercice: Affichez tous les adresses IP de yahoo.com
 

 4.5 La classe URL

Rappel

URL: Uniforme Resource Locator. 

Représente une chaîne de caractères qui permet localisation de manière unique une ressource sur le réseau Internet - le protocole à utiliser, la machine hôte(adresse IP+numero de port), le chemin d'accès(path), nom de la ressource(fichier):

protocole: //machine[:port]/chemin/nom

https://ff.tu-sofia.bg/JavaAv/network/Reseau.html

Description

Contient des méthodes pou créer et ouvrir des pages Web. Ne possède pas des variables.

Constructeurs

On peut construire un objet 

URL u1 = new URL("https", "ff.tu-sofia.bg", "/futurs-etudiants/");

URL u2 = new URL("https://ff.tu-sofia.bg/");

URL u3 = new URL(u2, "Java/Network.htm");  // https://ff.tu-sofia.bg/Java/Network.html

Tous les constructeurs peuvent lever une MalformedURLException.

Les different types des objets URL sont utilisés avec des differents protocoles, le plus souvent avec http, https et ftp . Les URL pour ces protocoles sont utilisés pour localiser des differents fichiers, comme pages Web , images, fichiers multimedia, fichiers texte et les programmes téléchargeables. On peut les utiliser aussi bien pour les programmes executables, comme les scripts CGI.
 

 4.5.1 Exemple 

import java.net.MalformedURLException;
import java.net.URL;

public class Test
{
    public static void main(String[] args)
                throws MalformedURLException {

        // creates a URL with string representation.
        URL url1 =
        new URL("https://ff.tu-sofia.bg"+
             "/sites/default/files/documents_ff/FICHE_INSCRIPION-IC_002.pdf");

        // creates a URL with a protocol,host name,and path
        URL url2 = new URL("https", "ff.tu-sofia.bg",
                        "/futurs-etudiants/");
        
        //create a URL with another URL and path
        URL url3 = new URL("https://ff.tu-sofia.bg");
        URL url4 = new URL(url3, "/futurs-etudiants/");


        // print the String representation of the URL.
        System.out.println(url1.toString());
        System.out.println(url2.toString());
        System.out.println();
        System.out.println("Different components of the URL");

        // Retrieve the protocol for the URL
        System.out.println("Protocol url1: " + url1.getProtocol());

        // Retrieve the host name of the URL
        System.out.println("Hostname url1:  " + url1.getHost());

        // Retrieve the default port
        System.out.println("Default port url1: " + url1.getDefaultPort());


        // Retrieve the path of URL
        System.out.println("Path url4: " + url4.getPath());

        // Retrieve the file name
        System.out.println("File url1: " + url1.getFile());
    }
}

 

 4.5.2 On peut lier des classe I/O à un URL

Exemple:  copier in fichier binaire d'un URL

import java.io.*;
import java.net.*;
public class Test1 {
public static void main(String arg[]) {
int abyte;
try{
URL url = new URL("https://ff.tu-sofia.bg/sites/default/files/images/blogs/FF_Poster.jpg");
InputStream fi= url.openStream();
FileOutputStream fo= new FileOutputStream("picture.jpg");
System.out.println("srarting ...");
while((abyte= fi.read())!=-1)fo.write(abyte);
fi.close();
fo.close();
System.out.println("created");

}catch(MalformedURLException me) {
System.out.println("MalformedURLException: "+ me);
}catch (IOException ioe){
System.out.println("IOException: "+ ioe);
}

}
}

 4.5.3 Avec un tampon:

import java.io.*;
import java.net.*;
public class Test2 {
public static void main(String arg[]) throws MalformedURLException, IOException{
byte buf[]=new byte[1024];
int len;

URL url = new URL("https://ff.tu-sofia.bg/sites/default/files/images/blogs/FF_Poster.jpg");
InputStream fi= url.openStream();
FileOutputStream fo= new FileOutputStream("picture1.jpg");
System.out.println("srarting ...");
while((len= fi.read(buf))!=-1)fo.write(buf,0,len);
fi.close();
fo.close();
System.out.println("created");
}
}

 4.5.4 Exemple - affichage de code source d'une page URL 

import java.io.*;
import java.net.*;

class ReadURL{
   public static void main(String[] a){
      try{
         URL url = new URL("https://ff.tu-sofia.bg");
         BufferedReader br = new BufferedReader(new
                                  InputStreamReader(url.openStream()));
         String line;
         while((line=br.readLine()) !=null) {
            System.out.println(line);
         }
         br.close();
      }catch(MalformedURLException me) {
          System.out.println("MalformedURLException: "+ me);
      }catch (IOException ioe){
           System.out.println("IOException: "+ ioe);
      }
   }
}

 4.5.5 La classe URLConnection

Cette classe offre un meilleur contrôle sur le téléchargement d'information référencée par un URL

Construction - à deux pas 1) construire un URL  2)utiliser la fonction openConnection()

URL refg = new URL("https://ff.tu-sofia.bg");

URLConnection refg_c = refg.openConnection();

Avantages:

La classe dispose de méthodes permettant de connaître pour un contenu:
son type: getContentType()
son en-tête: getHeaderField() 

et d'autre information:

getContentEncoding()
getContentLength()
getDate()
getExpiration()
getLastModifed()

La classe permet d'écrire vers un URL pour fournir au serveur des données(cgi script)

Pour se faire il faut obtenir de la connexion un flot de sortie (OutputStream) (en utilisant getOutputStream() ) et donner la valeur true à la variable interne DoOutput (en utilisant setDoOutput(true)).

 

 4.6 Serveurs et clients

4.6.0 Introduction

serveur - écoute le réseau et attends quelqu'un de se connecter. Notion liée plutôt à l’application, non à la machine.
client - fait appel vers le serveur pour établir une connexion.

 

Sockets et ports

port - entier de type "int", software abstraction, second niveau d'adressage dans une machine pour identifier l'application serveur correspondante et le service assuré. Les ports 1 - 1024 sont réservés pour les services normalisés.
Chaque application - serveur - liée au port concret.

socket - software abstraction pour représenter les deux "terminaux" de la connexion entre les deux machines.
    ServerSocket - lie l'application serveur au port correspondant, écoute le réseau
    Socket - utilisé par l'application client pour se connecter et "causer". Utilisé par l'application serveur pour "causer" une fois la connexion établie.

procédure serveur:

procédure client:

 4.6.1 Exemple 1:  Client qui envoie un message SMTP

Extrait de rfc SMTP

++++++++++++++++
 3.5. OPENING AND CLOSING

At the time the transmission channel is opened there is an
exchange to ensure that the hosts are communicating with the hosts
they think they are.

The following two commands are used in transmission channel
opening and closing:

HELO <SP> <domain> <CRLF>

QUIT <CRLF>

In the HELO command the host sending the command identifies
itself; the command may be interpreted as saying "Hello, I am
<domain>".

+++++++++++++++++++++++++++++++++

=====================

                   Example of the SMTP Procedure

This SMTP example shows mail sent by Smith at host Alpha.ARPA,
to Jones, Green, and Brown at host Beta.ARPA. Here we assume
that host Alpha contacts host Beta directly.

S: MAIL FROM:<[email protected]>
R: 250 OK

S: RCPT TO:<[email protected]>
R: 250 OK

S: RCPT TO:<[email protected]>
R: 550 No such user here

S: RCPT TO:<[email protected]>
R: 250 OK

S: DATA
R: 354 Start mail input; end with <CRLF>.<CRLF>
S: Blah blah blah...
S: ...etc. etc. etc.
S: <CRLF>.<CRLF>
R: 250 OK

The mail has now been accepted for Jones and Brown. Green did
not have a mailbox at host Beta.
======================================================
voir RFC 821 - SMTP

Example 1

import java.net.*;
import java.net.*;
import java.io.*;

public class MailSend{
private static String messageSys[]= new String[4],
messageData[]=new String[5],hostName=null,
domain=".domain";
private static InetAddress mServer= null;
public static void init(){
int j=0;
try{
mServer=InetAddress.getByName("myMailServer.bg");
hostName= InetAddress.getLocalHost().getHostName();
}catch(Exception e){System.out.println("Exception"+e);}

messageSys[0]="HELO "+hostName+domain+"\r\n";
messageSys[1]="MAIL FROM: <[email protected]>\r\n";
messageSys[2]="RCPT TO: ";
messageSys[3]="DATA\r\n";
messageData[0]="From: [email protected]"+"\r\n";
messageData[1]="To:";
messageData[2]="Subject: ";
messageData[3]= "";
messageData[4]=".\r\n";

}
public static void putData(String arg[]){
messageSys[2]+=arg[0]+"\r\n";
messageData[1]+=arg[0]+"\r\n";
messageData[2]+= arg[1]+"\r\n";
messageData[3]= arg[2]+"\r\n";

}
public static void send (){
try{
Socket s=null;

s = new Socket(mServer,25);
BufferedReader in = new BufferedReader(
new InputStreamReader(s.getInputStream()));
PrintWriter out = new PrintWriter(s.getOutputStream());
System.out.println(in.readLine());
for(int i=0; i<messageSys.length;i++){
out.print(messageSys[i]);
System.out.println(messageSys[i]);
out.flush();
System.out.println(in.readLine());
}
for(int i=0;i<messageData.length;i++){
out.print(messageData[i]);
System.out.println(messageData[i]);
out.flush();
}
System.out.println(in.readLine());

out.print("QUIT\r\n");
System.out.println("QUIT\r\n");
out.flush();
System.out.println(in.readLine());

s.close();
}
catch(Exception e) {System.out.println(e); }
}
}

et l'interface utilisateur du programme:

import java.awt.*;
import java.awt.event.*;

class Gui{
TextArea ta;
TextField sb,to;
Label ls,lt;
Button send;
Panel p= new Panel();
Gui(Frame f){
ta = new TextArea(10,20);
send = new Button("send");
to = new TextField("",20);
lt= new Label("To:");
sb = new TextField("",20);
ls = new Label("Subject:");
send.addActionListener(new S());
p.add(lt);
p.add(to);
p.add(ls);
p.add(sb);
f.add(p,BorderLayout.NORTH);
f.add(ta, BorderLayout.CENTER);
f.add(send, BorderLayout.SOUTH);
MailSend.init();
}
class S implements ActionListener{
public void actionPerformed(ActionEvent e) {
String message[]= {to.getText(),sb.getText(),ta.getText()};
MailSend.putData(message);
MailSend.send();
}
}
static class WL extends WindowAdapter {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
}


public static void main(String args[]){
Frame frame =new Frame("Mail Sender");
Gui gui = new Gui(frame);
frame.setSize(500,300);
frame.addWindowListener(new WL());
frame.setVisible(true);
}
}

Exercice: Introduisez dans l'interface les annonces pour les problèmes possibles.


 4.6.2 Exemple 2: Un simple serveur et client:


// FirstServer.java
// Very simple server that just
// echoes whatever the client sends.
import java.io.*;
import java.net.*;

public class FirstServer {
  // Choose a port outside of the range 1-1024:
  public static final int PORT = 8080;
  public static void main(String[] args)
      throws IOException {
    ServerSocket s = new ServerSocket(PORT);
    System.out.println("Started: " + s);
    try {
      // Blocks until a connection occurs:
      Socket socket = s.accept();
      try {
        System.out.println(
          "Connection accepted: "+ socket);
        BufferedReader in =
          new BufferedReader(
            new InputStreamReader(
              socket.getInputStream()));
        // Output is automatically flushed
        // by PrintWriter:
        PrintWriter out =
          new PrintWriter(
            new BufferedWriter(
              new OutputStreamWriter(
                socket.getOutputStream())),true);
        while (true) {
          String str = in.readLine();
          if (str.equals("END")) break;
          System.out.println("Echoing: " + str);
          out.println(str);
        }
      // Always close the two sockets...
      } finally {
        System.out.println("closing...");
        socket.close();
      }
    } finally {
      s.close();
    }
  }
}


// Very simple client that just sends
// lines to the server and reads lines
// that the server sends.
import java.net.*;
import java.io.*;

public class FirstClient {
  public static void main(String[] args)throws IOException {
    // Passing null to getByName() produces the
    // special "Local Loopback" IP address, for
    // testing on one machine w/o a network:
    // Alternatively, you can use
    // the address or name:
    // InetAddress addr = InetAddress.getByName("127.0.0.1");
    // InetAddress addr = InetAddress.getByName("localhost");

    String serveur = null;
    InetAddress addr =  InetAddress.getByName(serveur);
    System.out.println("addr = " + addr);
    Socket socket = new Socket(addr, FirstServer.PORT);
    // Guard everything in a try-finally to make
    // sure that the socket is closed:
    try {
      System.out.println("socket = " + socket);
      BufferedReader in =
        new BufferedReader(
          new InputStreamReader(socket.getInputStream()));
      BufferedReader sin =  new BufferedReader(
new InputStreamReader(System.in));
      // Output is automatically flushed

      // by PrintWriter:
      PrintWriter out =
        new PrintWriter(
          new BufferedWriter(
            new OutputStreamWriter(
              socket.getOutputStream())),true);
      for(int i = 0; i <10 ; i ++) {
        System.out.println("input a line [empty for finish] " + i + ":");
        String s = sin.readLine();
         if(s.length()==0) break;

         out.println(s + "   :" +i);
         String str = in.readLine();
         System.out.println(str);
      }
      out.println("END");
    }
    finally {
      System.out.println("closing...");
      socket.close();
    }
  }
}



Resultats
 
>java FirstServer
Started: ServerSocket[addr=0.0.0.0/0.0.0.0,port=0,localport=8080]
Connection accepted: Socket[addr=127.0.0.1/127.0.0.1,port=1029,localport=8080]
Echoing: premiere ligne   :0
Echoing: deuxieme ligne   :1
Echoing: troisieme ligne   :2
closing...
>java FirstClient
addr = localhost/127.0.0.1
socket = Socket[addr=localhost/127.0.0.1,port=8080,localport=1033]
input a line [empty for finish] 0:
first line   :0
input a line [empty for finish] 1:
second line   :1
input a line [empty for finish] 2:
third line   :2
input a line [empty for finish] 3:
closing...

 

 4.6.3 Servir plusieurs clients

Il faut utiliser plusieurs threads:

//: MultiClientServer.java
// A server that uses multithreading to handle
// any number of clients.
import java.io.*;
import java.net.*;

class ServeOneClient extends Thread {
    private Socket socket;
    private BufferedReader in;
    private PrintWriter out;
    public ServeOneClient(Socket s)  throws IOException {
        socket = s;
        in = new BufferedReader(
                new InputStreamReader(
                  socket.getInputStream()));
    // Enable auto-flush:
        out = new PrintWriter( new BufferedWriter(
                                                   new OutputStreamWriter(
                                                     socket.getOutputStream()
                                                   )
                                              ),
                  true);
    // If any of the above calls throw an
    // exception, the caller is responsible for
    // closing the socket. Otherwise the thread
    // will close it.
        start();    // Calls run()
  }
  public void run() {
    try {
        while (true) {
             String str = in.readLine();
             if (str.equals("END")) break;
            System.out.println("Echoing: " + str);
            out.println(str);
        }
        System.out.println("closing...");
    } catch (IOException e) {  }
   finally {
      try {
        socket.close();
      } catch(IOException e) {}
    }
  }
}

public class MultiClientServer {
  static final int PORT = 8080;
  public static void main(String[] args) throws IOException {
    ServerSocket s = new ServerSocket(PORT);
    System.out.println("Server Started");
    try {
      while(true) {
        // Blocks until a connection occurs:
        Socket socket = s.accept();
        try {
          new ServeOneClient(socket);
        } catch(IOException e) {
          // If it fails, close the socket,
          // otherwise the thread will close it:
          socket.close();
        }
      }
    } finally {
      s.close();
    }
  }
}

 

 4.6.4 Clients portent noms:

// Client with name
import java.net.*;
import java.io.*;

public class ClientWithName {
   public static void main(String[] args)throws IOException {
   // Passing null to getByName() produces the
    // special "Local Loopback" IP address, for
    // testing on one machine w/o a network:
    // Alternatively, you can use
    // the address or name:
    // InetAddress addr = InetAddress.getByName("127.0.0.1");
    // InetAddress addr = InetAddress.getByName("localhost");

        String serveur = null;
    InetAddress addr = InetAddress.getByName(serveur);
    System.out.println("addr = " + addr);
    Socket socket = new Socket(addr, FirstServer.PORT);
    // Guard everything in a try-finally to make
    // sure that the socket is closed:
        try {
            System.out.println("socket = " + socket);
             BufferedReader sin = new BufferedReader(
                      new InputStreamReader(System.in));
            BufferedReader in =  new BufferedReader(
                  new InputStreamReader(socket.getInputStream()));
            // Output is automatically flushed
            // by PrintWriter:
            PrintWriter out = new PrintWriter(new BufferedWriter(
                      new OutputStreamWriter(socket.getOutputStream())),true);
            System.out.print("Your name: ");
            String name = sin.readLine();
            for(int i = 0; i <10 ; i ++) {
                System.out.println("input a line [empty for finish] :");
                String s = sin.readLine();
                if(s.length()==0) break;
                out.println(name+":"+s);
               String str = in.readLine();
               System.out.println(str);
           }
           out.println("END");
        } finally {
                System.out.println("closing...");
                socket.close();
        }
   }