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
[Link])) 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 [Link]
java net InetAddress permet de manipuler des adresses
IP
– Mode connecté (TCP)
• La classe [Link] permet de programmer
l'interface côté serveur
• La classe [Link]
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 [Link] et
[Link] permettent de programmer la
communication en mode datagramme
Cl
Classe [Link]
t I tAdd
• Conversion de nom vers adresse IP
– méthodes permettant de créer des objets adresses IP
• InetAddress [Link]() pour obtenir une
InetAddress de l’hôte
• InetAddress [Link](String id) pour
obtenir une InetAddress d’une machine donnée
• InetAddress[ ] [Link](String
InetAddress getAllByName(String id)
pour obtenir toutes les InetAddress d’un site
– Le p
paramètre id ppeut être un nom de machine ([Link]‐
(p p f
[Link]) ou un numéro IP ([Link])
– Ces 3 fonctions peuvent lever une exception
UnknownHostException
Cl
Classe [Link]
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 = [Link]();
[Link]([Link]());
[Link]([Link]());
} catch(UnknownHostException uhe){
[Link]("Inconnu !");
}
• Obtenir le nom et le numéro IP d’une autre machine :
try{
I tAdd
InetAddress uneAdresse
Ad = [Link](nom);
I tAdd tB N ( )
[Link]([Link]());
[Link]([Link]());
} catch(UnknownHostException uhe){
[Link]("Inconnu !");
}
Cl
Classe [Link]
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 [Link]
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 [Link]
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 = [Link]();
// et création du socket clientServiceSocket si
// acceptation
p de la connexion
…
}
catch(IOException ioe) { . . . }
Cl
Classe [Link]
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 [Link]
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 [Link]
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 [Link]
tS k t
• La communication effective sur une connexion par socket
utilise la notion de flots de données
(java io OutputStream et [Link])
([Link] 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([Link]());
String chaine = [Link]();
ou
BufferedReader entree = new BufferedReader(
new InputStreamReader([Link]()));
String
St g c
chaine
a e = [Link]();
t ee. ead e();
Cl
Classe [Link]
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([Link]());
[Link](chaine);
ou
PrinterWriter sortie = new PrinterWriter ([Link]());
[Link](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 (
[Link] () ));
while (true){
String message = [Link]();
[Link](message);
}
}catch(UnknownHostException uhe){
[Link]("UnknownHostException");
}catch(IOException ioe){
[Link]([Link]());
}
Client / serveur en mode connecté
(très simplifié)
Sur un client Sur le serveur (prevert
([Link])
upmf grenoble fr)
doit être connu
du client
serveurSocket = new ServerSocket(8254);
clientSocket = new Socket("prevert
Socket( [Link]
upmf grenoble fr", 8254); clientServiceSocket = [Link]();
serveurSocket accept();
Le client et le serveur sont à présent connectés
PrintWriter sortie = new printWriter ( PrintWriter sortie = new printWriter (
[Link](), true); [Link](), true);
BufferedReader entree = new BufferedReader ( BufferedReader entree = new BufferedReader (
new InputStreamReader( new InputStreamReader(
[Link]())); clientServiceSocket getInputStream()));
[Link]()));
Le client et le serveur peuvent maintenant communiquer
BufferedReader clavier = new BufferedReader(
new InputStreamReader([Link]));
String requete;
St i requete,
String t reponse; String reponse;
while (true) { while (true) {
requete = [Link](); // utilisateur entre la requête requete = [Link]();
sortie println(requete); // envoyer la requête au serveur
[Link](requete); // exécuter le service
reponse = [Link](); // attendre la réponse // envoyer la réponse au client
[Link](reponse); // afficher la réponse [Link](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 [Link] = socket;
}
public void run() {
serveurSocket = new ServerSocket(8254); PrintWriter sortie = new p
printWriter (
[Link](), true);
while (true) { BufferedReader entree = new BufferedReader (
Socket clientServiceSocket = [Link](); new InputStreamReader(
[Link]()));
Service monService = new Service(clientServiceSocket);
// crée un nouveau thread pour le nouveau client try {
[Link](); requete = [Link]();
// lance l’exécution du thread // exécuter le service
} // envoyer la
l réponse
é au client
li t
[Link](reponse);
} finally {
[Link]();
Le programme du client }
est inchangé }
}