L’API socket en java
LAPI
L’API socket
k t en Java
J
• L'i
L'interface
f Java
J des
d sockets
k (package
( k j
java.net)) offre
ff un
accès simple aux sockets sur IP
• Plusieurs
Pl i classes
l interviennent
i t i t lors
l de d la
l réalisation
é li ti d'une
d'
communication par sockets
– La classe java.net.InetAddress
java net InetAddress permet de manipuler des adresses
IP
– Mode connecté (TCP)
• La classe java.net.SocketServer permet de programmer
l'interface côté serveur
• La classe java.net.Socket
java net Socket permet de programmer l'interface
l interface
côté client et la communication effective par flot d’octets
– Mode non connecté (UDP)
• Les classes java.net.DatagramSocket et
java.net.DatagramPacket permettent de programmer la
communication en mode datagramme
Cl
Classe jjava.net.InetAddress
t I tAdd
• Conversion de nom vers adresse IP
– méthodes permettant de créer des objets adresses IP
• InetAddress InetAddress.getLocalHost() pour obtenir une
InetAddress de l’hôte
• InetAddress InetAddress.getByName(String id) pour
obtenir une InetAddress d’une machine donnée
• InetAddress[ ] InetAddress.getAllByName(String
InetAddress getAllByName(String id)
pour obtenir toutes les InetAddress d’un site
– Le p
paramètre id ppeut être un nom de machine (prevert.upmf‐
(p p f
grenoble.fr) ou un numéro IP (195.221.42.159)
– Ces 3 fonctions peuvent lever une exception
UnknownHostException
Cl
Classe jjava.net.InetAddress
t I tAdd
• Conversions inverses
– Des méthodes applicables
pp à un objet
j de la classe
InetAddress permettent d'obtenir dans divers
formats des adresses IP ou des noms de site
• String getHostName() obtient le nom complet
correspondant
p à l'adresse IP
• String getHostAddress() obtient l'adresse IP
sous forme %d.%d.%d.%d
• byte[] getAddress() obtient l'adresse IP sous
forme d'un tableau d'octets
Exemples
• Obtenir le nom et le numéro IP de la machine sur laquelle on
travaille :
try{
InetAddress monAdresse = InetAddress.getLocalHost();
System.out.println(monAdresse.getHostName());
System.out.println(monAdresse.getHostAddress());
} catch(UnknownHostException uhe){
System.out.println("Inconnu !");
}
• Obtenir le nom et le numéro IP d’une autre machine :
try{
I tAdd
InetAddress uneAdresse
Ad = InetAddress.getByName(nom);
I tAdd tB N ( )
System.out.println(uneAdresse.getHostName());
System.out.println(uneAdresse.getHostAddress());
} catch(UnknownHostException uhe){
System.out.println("Inconnu !");
}
Cl
Classe jjava.net.ServerSocket
tS S k t
• Cette classe implante un objet ayant un comportement de
serveur via
i une interface
i t f par socket
k t
• Constructeurs
– S
ServerSocket(int
S k t(i t port) t)
– ServerSocket(int port, int backlog)
– ServerSocket(int port, port int backlog,
backlog
InetAddress bindAddr)
• Créent un objet serveur à l'écoute du port spécifié
• La taille de la file d'attente des demandes de connexion peut
être explicitement spécifiée via le paramètre backlog
• Si la machine possède plusieurs adresses,
adresses on peut aussi
restreindre l'adresse sur laquelle on accepte les connexions
Cl
Classe jjava.net.ServerSocket
tS S k t
• Méthodes
– Socket accept() accepte une connexion entrante
• Méthode bloquante, mais dont l'attente peut être limitée dans le
temps par l'appel préalable de la méthode setSoTimeout (voir
plus loin)
– void close() ferme la socket
– InetAddress getInetAddress() retourne l’adresse du
serveur
– int getLocalPort() retourne le port sur lequel le
serveur écoute
Cl
Classe jjava.net.ServerSocket
tS S k t
• Une ServerSocket serveur permet à des clients
de se connecter,
connecter la connexion étant ensuite gérée par
une Socket
// création d’un socket serveur sur le port port
ServerSocket serveurSocket = new ServerSocket(port);
try{
while(true){
// Attente de la connexion d’un
d un client
Socket clientServiceSocket = serveurSocket.accept();
// et création du socket clientServiceSocket si
// acceptation
p de la connexion
…
}
catch(IOException ioe) { . . . }
Cl
Classe jjava.net.Socket
tS k t
• Cette classe est utilisée pour la programmation des
sockets connectées, côté client et côté serveur
• Constructeurs
– Socket(String host, int port)
• Construit une nouvelle socket en tentant une
connexion à la machine hôte host sur le port port
• Levée dd’exception
exception :
– UnknownHostException si la machine hôte
n’existe
n existe pas
– IOException s’il n’y a pas d’application
serveur démarrée sur le port p
Cl
Classe jjava.net.Socket
tS k t
• Constructeurs
C t t (suite)
( it )
– Socket(InetAddress address, int port)
• Construit
C i une nouvelle
ll socket
k en tentant une
connexion à la machine hôte d’adresse address sur
le port port
• Levée d’exception :
– IOException s’il n’y a pas d’application serveur
dé
démarrée
é sur le
l port p
• Deux autres constructeurs permettent en outre de fixer
ll'adresse
adresse IP et le numéro de port utilisés côté client (plutôt
que d'utiliser un port disponible quelconque)
– Socket(String g host, int p port,
InetAddress localAddr, int localPort)
– Socket(InetAddress addr, int port,
InetAddress localAddr,
localAddr int localPort)
Cl
Classe jjava.net.Socket
tS k t
• Méthodes
Mé h d
– void close() fermeture de la socket (peut lever une exception
IOException)
– void shutDownInput() fermeture de la socket pour la
lecture (p
(peut lever une exception
p IOException)
p )
– void shudownOutput() fermeture de la socket pour l’écriture
(peut lever une exception IOException)
– InetAddress getLocalAddress() : adresse de la machine
hôte
– InetAddress geInetAddress() : adresse de la machine à
laquelle on est connecté
– int g getLocalPort() : le port local
– int getPort() : le port sur la machine distante
Cl
Classe jjava.net.Socket
tS k t
• La communication effective sur une connexion par socket
utilise la notion de flots de données
(java io OutputStream et java.io.InputStream)
(java.io.OutputStream java io InputStream)
• Méthode utilisée pour obtenir les flots en entrée (lecture)
– InputStream getInputStream()
– InputStream doit être « habillé » par :
• DataInputStream
• InputStreamReader
p
• Exemples
Socket socket …
DataInputStream entree = new DataInputStream(socket.getInputStream());
String chaine = entree.readUTF();
ou
BufferedReader entree = new BufferedReader(
new InputStreamReader(socket.getInputStream()));
String
St g c
chaine
a e = eentree.readLine();
t ee. ead e();
Cl
Classe jjava.net.Socket
tS k t
• Méthode utilisée pour obtenir les flots en sortie (écriture)
– OutputStream getOutputStream()
– OutputStream doit être « habillé » par :
• DataOutputStream
• PrinterWriter
• Exemples
Socket
S k t socket
k t …
DataOutputStream sortie = new DataOutputStream(socket.getOutputStream());
sortie.writeUTF(chaine);
ou
PrinterWriter sortie = new PrinterWriter (socket.getOutputStream());
sortie.println(chaine);
• Remarque
• les opérations sur les sockets et les flots sont bloquantes :
l’application est arrêtée tant que l’opération n’est pas terminée
(Î utilisation des threads)
S k t Options
Socket O ti
• TCP_NODELAY :
– void setTcpNoDelay(boolean b) et boolean getTcpNoDelay()
• vrai : implique
l que les
l paquets sont envoyés
é sans délai
dél
• faux :
– les petits paquets sont regroupés avant d’être envoyés
– le
l système
è attend
ddde recevoir
i le
l message d’acquittement
d’ i du
d paquet précédent,
é éd avant
d’envoyer le paquet suivant (algorithme de Nagle)
• SO_LINGER :
– void setSoLinger(boolean b, int s) et int getSoLinger()
• ce paramètre indique ce qu’il faut faire des paquets non encore envoyés lorsque
la socket est fermée
• faux : la socket est fermée immédiatement, et les paquets non envoyés perdus
• vrai : la fermeture de la socket bloque pendant s secondes, pendant lesquelles
les données peuvent être envoyées, et les acquittements reçus
S k t Options
Socket O ti
• SO_TIMEOUT :
– void setSoTimeout(int timeout) et int getSoTimeout()
• Prendd en paramètre
è le l délai
dél de
d garded expriméé en millisecondes
ll d
• La valeur par défaut 0 équivaut à l'infini
• À l'expiration du délai de garde, l'exception InterruptedIOException est levée
• SO_SNDBUF :
– void setSendBufferSize(int s) et int getSendBufferSize()
• SO_RCVBUF :
– void setReceiveBufferSize(int s)
et int getreceiveBufferSize()
• permettent d’ajuster la taille des tampons pour augmenter les performances ; on
utilisera des tampons
p p
plus ggrands si :
– le réseau est rapide
– de gros blocs de données sont transférés (FTP, HTTP)
S k t Options
Socket O ti
• SO_KEEPALIVE :
– void setKeepAlive(boolean b) et boolean getKeepAlive()
– quand l’option est mise à vrai : s’il n’y a pas eu de transfert de données sur la
socket depuis 2 heures (en général), TCP envoie un paquet au partenaire. 3
possibilités :
• Le partenaire répond par un message d’acquittement
d acquittement (ACK)
(ACK), tout est OK
• Le partenaire répond avec un RST ; le partenaire a eu une interruption, suivie d’un
redémarrage: la socket est fermée
• Pas de réponse du partenaire : la socket est fermée
Cli t en mode
Client d connecté
té
BufferedReader entree;
try{
clientSocket = new Socket(hote, port);
entree
t = new BufferedReader(new
B ff dR d ( I
InputStreamReader
tSt R d (
clientSocket.getInputStream () ));
while (true){
String message = entree.readLine();
System.out.println(message);
}
}catch(UnknownHostException uhe){
System.out.println("UnknownHostException");
}catch(IOException ioe){
System.out.println(ioe.getMessage());
}
Client / serveur en mode connecté
(très simplifié)
Sur un client Sur le serveur (prevert
(prevert.upmf-grenoble.fr)
upmf grenoble fr)
doit être connu
du client
serveurSocket = new ServerSocket(8254);
clientSocket = new Socket("prevert
Socket( prevert.upmf-grenoble.fr
upmf grenoble fr", 8254); clientServiceSocket = serveurSocket.accept();
serveurSocket accept();
Le client et le serveur sont à présent connectés
PrintWriter sortie = new printWriter ( PrintWriter sortie = new printWriter (
clientSocket.getOutputStream(), true); clientServiceSocket.getOutputStream(), true);
BufferedReader entree = new BufferedReader ( BufferedReader entree = new BufferedReader (
new InputStreamReader( new InputStreamReader(
clientSocket.getInputStream())); clientServiceSocket getInputStream()));
clientServiceSocket.getInputStream()));
Le client et le serveur peuvent maintenant communiquer
BufferedReader clavier = new BufferedReader(
new InputStreamReader(System.in));
String requete;
St i requete,
String t reponse; String reponse;
while (true) { while (true) {
requete = clavier.readLine(); // utilisateur entre la requête requete = entree.readLine();
sortie println(requete); // envoyer la requête au serveur
sortie.println(requete); // exécuter le service
reponse = entree.readLine(); // attendre la réponse // envoyer la réponse au client
System.out.println(reponse); // afficher la réponse sortie.println(reponse);
} }
Un serveur concurrent en mode
connecté (schéma veilleur-
veilleur-exécutants)
Programme des exécutants public class Service extends Thread {
protected final Socket socket;
String requete, reponse;
public monService(Socket socket) {
Programme
g du veilleur this.socket = socket;
}
public void run() {
serveurSocket = new ServerSocket(8254); PrintWriter sortie = new p
printWriter (
clientServiceSocket.getOutputStream(), true);
while (true) { BufferedReader entree = new BufferedReader (
Socket clientServiceSocket = serveurSocket.accept(); new InputStreamReader(
clientServiceSocket.getInputStream()));
Service monService = new Service(clientServiceSocket);
// crée un nouveau thread pour le nouveau client try {
monService.start(); requete = entree.readLine();
// lance l’exécution du thread // exécuter le service
} // envoyer la
l réponse
é au client
li t
sortie.println(reponse);
} finally {
socket.close();
Le programme du client }
est inchangé }
}