Socket :
Communication via le réseau
un premier
socket
Source de SocketClient1.java
import java.io.*;
import java.net.*;
public class SocketClient1 {
public static void main(String args[]) {
if (args.length != 2)
System.out.println("usage : SocketClient1 hote port");
else {
Socket soc = null;
String hote = args[0];
int port = Integer.valueOf(args[1]).intValue();
try {
soc = new Socket(hote, port);
BufferedReader socIn = new BufferedReader(
new InputStreamReader(soc.getInputStream()));
String ligne;
while ((ligne = socIn.readLine()) != null)
System.out.println(ligne);
} catch (UnknownHostException e) {
System.out.println("hote "+ hote +" inconnu : "+e.getMessage());
} catch (IOException e) {
System.out.println("erreur entree/sortie : "+e.getMessage());
}
}
}
}
|
EXECUTION avec 2 terminaux
$ javac DayTimeServer.java
$ java DayTimeServer
start DayTime server sur port : 1313
|
$ java SocketClient1 localhost 1313
Tue Dec 13 12:16:57 2005
|
Les lignes de la classe :
lecture
et écriture dans un socket
Source de ClientEcho.java
import java.io.*;
import java.net.*;
import java.util.Scanner;
public class ClientEcho {
public static void main(String[] args) throws IOException {
if (args.length != 1) {
System.out.println("Usage : java ClientEcho hostName" );
System.exit(1);
}
String hostName = args[0];
Socket sock = null;
PrintWriter sockOut = null;
BufferedReader sockIn = null;
try {
sock = new Socket(hostName, 7777);
sockOut = new PrintWriter(sock.getOutputStream(), true);
sockIn = new BufferedReader(new InputStreamReader(
sock.getInputStream()));
} catch (UnknownHostException e) {
System.err.println("host non atteignable : "+hostName);
System.exit(1);
} catch (IOException e) {
System.err.println("connection impossible/cassee avec : "+hostName);
System.exit(1);
}
System.out.println("tapez q pour terminer");
Scanner scan = new Scanner(System.in);
String message = scan.next().toLowerCase();
while (! message.equals("q")) {
sockOut.println(message);
String recu = sockIn.readLine();
if (recu == null) {
System.out.println("erreur de connection");
break;
}
System.out.println("echo: " + recu.trim());
message = scan.next().toLowerCase();
}
sockOut.close();
sockIn.close();
sock.close();
}
}
|
EXECUTION sur plusieurs terminaux
$ javac ServeurEcho.java
$ java ServeurEcho
|
$ java ClientEcho localhost
tapez q pour terminer
coucou
echo: coucou
bonjour
echo: bonjour
q
$ java ClientEcho localhost
world
echo: world
...
|
Les lignes de la classe :
- Il faut mettre préalablement en
exécution un serveur d'échos
donc lancez ServeurEcho sur une console différente
- on peut exécuter de nouveaux clients
tant que le serveur fonctionne
- par contre, un seul client est servi à
la fois
- si on arrete le serveur par un <ctrl>C,
un message "erreur de connection" est affiché
- si on exécute le client sans le
serveur, un message "connection impossible avec ..."
est affiché
|
- close()
ferme proprement le socket
est susceptible de lever une exception UnknownHostException
- getOutputStream()
retourne un flux de sortie OutputStream pour le socket.
- PrintWriter(OutputStream,
modeFlush)
instancie un "printer" de texte
si le modeFlush est true, à chaque appel de la méthode
println, un appel à flush() sera immédiatement
effectuée après.
Communication
par socket dans le "kernel"
- Les sockets furent proposées dans
la distribution BSD de Berkeley pour les communications réseaux
du système UNIX
- Leur utilisation respecte le schéma
"Open-Read-Write-Close" d'UNIX pour les entrées-sorties.
- L'adressage du destinataire de la communication
est composée de l'adresse Internet de la machine distante
et d'un numéro de port.
- La communication nécessite une
paire de sockets : un pour chacun des 2 programmes communiquants
via le réseau.
- Les données sont donc transférées
d'un socket à l'autre : un mécanisme de "buffer"
permet de ne pas se soucier de la transmission sur le réseau.
- A chaque mode de communication IP utilisé
: UDP ou TCP, correspond un type de socket
- UDP : le protocol des datagrammes utilise
les DatagramSocket
- Une image équivalente serait l'expédition
de lettres
- Dans ce mode non connecté, chaque
message est transmis avec l'adresse du socket destination et
celui du socket émetteur
- La transmission n'est pas sure et les
messages peuvent arriver dans le désordre.
- Un même socket peut être utilisé
pour envoyer et recevoir des messages à plusieurs interlocuteurs.
- Et le "multicast" est possible.
- TCP : mode connecté
- Tout d'abord, la connection doit être
établie entre les sockets
- Tant que la connection est maintenue,
la transmission peut se faire dans les 2 sens : sur chaque socket
il est possible de recevoir et d'émettre, donc 2 fluxs
par socket.
- Pour établir la connection, il
faut qu'un programme prenne l'initiative : ce sera le client,
tandis que l'autre doit être à l'écoute et/ou
l'attente : ce sera le serveur.
- La transmission est sans erreur.
class
Socket
- constructeurs
- Socket()
crée un socket sans connection
- Socket(hostname, numeroPort)
- Socket(InetAddress address, port)
utilise l'adresse IP : InetAdress
- méthodes
- close()
- getOutputStream()
- getInputStream()
- getLocalPort()
retourne le numéro de port local
- getPort()
retourne le numéro de port distant auquel le socket est
connecté.
- InetAddress getInetAddress()
retourne l'adresse de la machine distante
- la classe InetAddress représente
une adresse IP et éventuellement le nom de la machine
méthodes :
- getHostAdress()
retourne l'IP sous forme de String
- getHostName()
retourne le nom d'hote
- isClosed()
indique si le socket est fermé. Ne pas faire de boucle d'attente avec !
- isConnected()
retourne l'état de la connexion du socket. Ne pas faire de boucle d'attente avec !
- connect(SocketAddress adresseSocket)
connecte le socket au serveur
- connect(SocketAddress adresseSocket, int timeout)
connecte le socket au serveur avec une valeur d'expiration en
millisecondes SO_TIMEOUT
lève une SocketTimeoutException si le délai à
expiré.
- SocketAddress
est une classe abstraite
- InetSocketAddress
hérite de SocketAddress
est une classe représentant une InetAddress et un port
- InetSocketAddress(InetAddress ina,
int port)
- InetSocketAddress(String hostName,
int port)
- getAddress()
retourne l'InetAddress
- getHostname()
- getPort()
- getRemoteSocketAddress()
retourne l'adresse de la machine distante auquel le socket est
connecté
- SocketChannel getChannel()
retourne l'objet SocketChannel associé au socket, s'il
y a !
- setSoTimeOut(int
timeout)
spécifie une valeur d'expiration en millisecondes SO_TIMEOUT
pour la méthode bloquante le lecture read()
la valeur 0 correspond à un délai infini
lève une InterruptedIOException si le délai a expiré.
- getSoTimeOut()
- getReceiveBufferSize()
donne la taille de la mémoire tampon utilisée pour
le flot de lecture du socket.
- setReceiveBufferSize(size)
affecte la taille de la mémoire tampon utilisée
pour le flot de lecturedu socket.
- getSendBufferSize()
idem pour le tampon utilisé pour le flot d'écriture
du socket.
- setSendBufferSize()
byte et char
: caractère transmis et caractère JAVA
Pour les caractères, le langage JAVA
utilise le type char basé sur l'Unicode codé sur
16 bits.
Les transmissions sur les réseaux est basé sur l'octet
: 8 bits. Il est commode d'y transmettre des caractères
ASCII (7 bits).
Les methodes de télécommunication de JAVA sont donc
basées sur le transfert d'octets (byte).
Voici comment convertir un String en byte[ ] et réciproquement
:
byte[] buffer = new byte[100];
String chaine = "Ceci est une chaine";
byte[] message ;
// conversion String vers byte[]
message = chaine.getBytes();
// conversion byte[] vers String
chaine = new String(message);
// idem mais un morceau du buffer
chaine = new String(buffer, 3, 25);
|
Le serveur d'Echo
Source de ServerEcho.java
import java.net.*;
import java.io.*;
class ServerEcho {
public static void main(String args[]) {
ServerSocket server = null;
try {
server = new ServerSocket(7777);
while (true) {
Socket sock = server.accept();
System.out.println("accept");
PrintWriter sockOut = new PrintWriter(
sock.getOutputStream(), true);
BufferedReader sockIn = new BufferedReader(
new InputStreamReader(sock.getInputStream()));
String recu;
while ((recu = sockIn.readLine()) != null) {
System.out.println("recu :"+recu);
sockOut.println(recu);
}
sockIn.close();
sockOut.close();
sock.close();
}
} catch (IOException e) {
System.out.println(e.getMessage());
} finally {
try {
server.close();
} catch (IOException e2) {
System.out.println(e2.getMessage());
}
}
}
}
|
Les lignes de la classe :
- le programme crée un serveur de
socket sur son port 7777
- puis l'appel à accept() met le
server en attente d'une connection d'un client
- à réception d'une connection
d'un client, un socket est crée pour assurer la communication.
- lorsque le client a fini, le programme
ferme le socket avec ce client
- et se remet en boucle d'attente d'une
connection d'un client
|
EXECUTION
$ java ServerEcho
accept
recu:coucou
recu:bonjour
accept
recu:world
....
|
La séquence correspond exactement
aux demandes des clients ci-dessus.
Tapez <ctrl>C pour arrêter
le serveur |
class ServerSocket
- La classe ServerSocket
implémente les sockets de connection du côté
du serveur.
- ServerSocket(numeroPort)
crée un objet ServerSocket sur ce numéro de port.
- accept()

attend une connection
d'une machine cliente
- à l'arrivée d'une demande
de connection d'une machine cliente,
un socket est crée pour connecter ce client au serveur
c'est l'objet retourné par la méthode bloquante
accept()
- close()
ferme le SocketServer et toutes les sockets en cours obtenus
par sa méthode accept.
- ServerSocket(numeroPort,
int backlog)
crée un objet ServerSocket sur ce numéro de port
avec une queue d'attente de connection de taille spécifiée
par l'entier backlog
par défaut, la taille est 50
les demandes de connections, quand la queue est pleine, sont
rejetées et provoque une exception du coté du client.
- getLocalPort()
retourne le numéro de port local
- InetAddress getInetAddress()
retourne l'adresse du serveur
- isClosed()
indique si le socket est fermé. Ne pas faire de boucle d'attente avec !
- setSoTimeOut(int
timeout)
spécifie une valeur d'expiration en millisecondes SO_TIMEOUT
pour la demande de connection d'un client
la valeur 0 correspond à un délai infini
lève une SocketTimeoutException si le délai a expiré.
- getSoTimeOut()
- accept()
attend une connection d'une machine cliente selon le délai
d'expiration SO_TIMEOUT
l'écoulement du délai lève une SocketTimeoutException
Les "Schémas"d'écriture
des sockets
- Créer un socket sans délai
d'expiration
Socket sock = null;
try {
InetAddress addr = InetAddress.getByName("xxx.yyy.zzz");
int port = XYZ;
sock = new Socket(addr, port);
} catch (UnknownHostException e) {
} catch (IOException e) {
}
|
- le constructeur de Socket bloque tant
que la connection n'est pas établie
- Créer un socket avec un "timeout"
Socket sock = null;
try {
InetAddress addr = InetAddress.getByName("xxx.yyy.zzz");
int port = XYZ;
SocketAddress sockAddr = new InetSocketAddress(addr, port);
sock = new Socket();
int timeOut = 3000;
sock.connect(sockAddr, timeOut);
} catch (UnknownHostException e) {
} catch (SocketTimeoutException e) {
} catch (IOException e) {
}
|
- le constructeur de Socket crée
un socket sans connection : "unbound"
- le délai est en millisecondes donc
3 secondes
- une demande de connection bloque jusquà
ce que la connection soit établie ou que le délai
d'expiration est écoulé
- si le délai à expiré,
une SocketTimeoutException est levée
- coté serveur, créer un
serveur de socket à l'écoute sur un port
ServerSocket servSock = null;
try {
int port = XYZ;
servSock = new ServerSocket(port);
} catch (IOException e) {
}
|
- un serveur de socket est établit
sur un port du serveur
- il fournira un socket à chaque
demande de connection d'un client
- Le serveur de socket est un socket particulier
ne traitant que les demandes de connection
- écouter et fournir les demandes
de connection
Socket sock = null;
try {
sock = servSock.accept();
} catch (IOException e) {
}
|
- le serveur de socket attend une demande
de connection d'un client sur son port d'écoute
- à réception d'une demande
de connection d'un client, il crée un socket "privé"
pour communiquer avec le client
- lecture directe du stream d'un socket
InputStream sockIn = socket.getInputStream();
byte[] buffer = new byte[1024];
int lu;
try {
while((lu = sockIn.read(buffer)) != -1)
System.out.write(buffer, 0, lu);
// fin de flot atteinte
} catch (IOException e) {}
|
- on récupère le flux de lecture
InputStream du socket
- On l'utilise directement pour lire des
"bytes"
- read(buffer) retourne -1 quand la fin
de flot est atteinte
- read() lit un seul byte et renvoie -1
si la fin de flot est atteinte
- la fin de flot peut être normale
(écriture close) ou accidentelle (déconnection
ou fin de processus ecrivain)
- les opérations de lecture peuvent
lever une IOException
- écriture directe dans le stream
d'un socket
OutputStream sockOut = socket.getOutputStream();
byte[] buffer = new byte[1024];
buffer = "chaine a écrire".getBytes();
try {
sockOut.write(buffer, 0, 12);
sockOut.flush();
sockOut.write(buffer);
} catch (IOException e) {}
|
- on récupère le flux d'écriture
OutputStream du socket
- On l'utilise directement pour écrire
des "bytes"
- write(buffer, pos, nbre) ecrit nbre bytes
à partir de la position indiquée
- write(buffer) écrit tous les bytes
du buffer
- flush() "devrait forcer" l'écriture
du contenu du tampon sur le flot .....
- les opérations d'écriture
et flush peuvent lever une IOException
en particulier, une tentative d'écriture sur un flot fermé
Lecture et écriture
de "plus haut niveau"
- lecture ligne par ligne de texte d'un
socket
try {
BufferedReader sockReader = new BufferedReader(
new InputStreamReader(socket.getInputStream()));
String ligne;
while ((ligne = sockReader.readLine()) != null) {
System.out.println(ligne);
}
} catch (IOException e) {}
|
- on crée un BufferedReader attaché
au flux InputStream
- on peut lire alors directement des caractères
(char JAVA) par readLine()
- readLine() renvoie la ligne lue sans le/les
caractères de fin de ligne
et null si la fin de flot est atteinte
- read() lit un seul caratère (char)
et renvoie -1 si la fin de flot est atteinte
- écriture de texte dans un socket
PrintWriter sockWriter = new PrintWriter(socket.getOutputStream()));
sockWriter.print("chaine String");
sockWriter.print(1234);
sockWriter.print(12.34);
sockWriter.flush();
sockWriter.println(true);
|
- on crée un PrintWriter attaché
au flux OutputStream
- on peut lire alors directement n'importe
quel type JAVA par print ou println
- c'est la représentation en chaine
de caractères (toString()) qui est utilisée
- flush() force l'écriture du contenu
du tampon sur le flot, s'il y a un tampon
- un autre constructeur PrintWriter(OutputStream,
boolean) précise le mode "autoflush" :
si true, alors chaque appel à println() provoque un flush()
- println() ajoute une fin de ligne dépendante
de la plateforme aux données écrites
toutes
ces méthodes ne génèrent pas d'Exception
elles sont pratiques mais "insécure"
- lecture de données JAVA à
partir d'un socket
DataInputStream sockDataIn = null;
try {
sockDataIn = new DataInputStream(socket.getInputStream());
byte by = sockDataIn.readByte();
char c = sockDataIn.readChar();
boolean bo = sockDataIn.readBoolean();
int i = sockDataIn.readInt();
double d = sockDataIn.readDouble();
String s = sockDataIn.readUTF();
} catch (EOFException e) {
} catch (IOException e) {
}
|
- DataInputStream permet de lire tous les
types primitifs JAVA sur tous les systèmes.
- readByte() retourne le prochain octet
- readChar() retourne le prochain caractère
unicode
- readBoolean() lit un octet et retourne
true si l'octet est != 0
- readInt() lit 4 octets et retourne l'entier
correspondant
- readDouble() lit 8 octets et retourne
le double correspondant
- readUTF() décode les octets en
caractère unicode si possible et retourne le String ainsi
formé
toutes
les méthodes ci-dessus lèvent l'exception EOFException
si la fin de flot est atteinte
- écriture de données JAVA
dans un socket
DataOutputStream sockDataOut = null;
try {
sockDataOut = new DataOutputStream(socket.getOutputStream());
int by = 0x6;
sockDataOut.writeByte(by);
int c = 'c';
sockDataOut.writeChar(c);
sockDataOut.writeBoolean(true);
sockDataOut.writeInt(-1234);
sockDataOut.writeDouble(12.34);
sockDataOut.flush();
sockDataOut.writeUTF("chaine String");
} catch (IOException e) {
}
|
- DataOutputStream permet d'écrire
tous les types primitifs JAVA sur tous les systèmes.
- writeByte(int) écrit le premier
octet de l'entier
- writeChar(int) écrit le caractère
unicode correspondant aux 2 premiers octets de l'entier
- writeBoolean(boolean) écrit le
booléen sur un octet
- writeInt(int) écrit l'entier sur
4 octets
- writeDouble(double) écrit le double
sur 8 octets
- flush() "devrait forcer" l'écriture
du contenu du tampon sur le flot, s'il y a un tampon
- writeUTF(String) écrit le String
en l'encodant en "UTF-8 modifié"
- transmission "sécure"
de données en passant par une représentation "caractère"
try {
OutputStream sockOut = socket.getOutputStream();
byte[] buffer = new byte[1024];
String envoi = "chaine String"+" " +(-1234)
+" "+12.34+" "+true;
buffer = envoi.getBytes();
sockOut.write(buffer, 0, envoi.length());
sockOut.flush();
} catch (IOException e) {}
|
- écriture en utilisant les séparateurs
par défaut : l'espace, le passage à la ligne ou
la tabulation
InputStream sockIn = socket.getInputStream();
byte[] buffer = new byte[1024];
int lu=0;
try {
lu = sockIn.read(buffer);
if (lu == -1)
// fin de flot atteinte
else
{
Scanner scan = new Scanner(new String(buffer));
String premierMot = scan.next());
String secondMot = scan.next());
if (scan.hasNextInt())
int entier = scan.nextInt());
else
String troisieme = scan.next());
if (scan.hasNextFloat())
float reel = scan.nextFloat());
else
String quatrieme = scan.next());
if (scan.hasNextBoolean())
boolean booleen = scan.nextBoolean());
else
String cinquieme = scan.next());
}
} catch (IOException e) {
// lecture impossible }
} catch (IllegalStateException) {
// si le scanner est fermé
} catch (InputMismatchException) {
// si le type de donnée est incompatible
} catch (NoSuchElementException) {
// s'il n'y a pas de donnée }
|
- la classe Scanner
- est pratique pour lire des données
à partir de leurs représentations en caractères
- elle utilise les sépararateurs
par défaut ou ceux qu'on spécifie
- la fin de flot ne donne pas d'IOException
Transmission d'objet
par réseau
Mise en place d'un ToutouService
Nous utilisons une classe Chien5.java :
public class Chien5
implements Serializable {
String nom;
String aboiement;
int nombrePuce;
Chien5(String s, String a, int i)
int getNombrePuce()
String getNom()
void setNombrePuce(int p)
void seGratte(int fois)
public boolean equals(Object autre)
public String toString()
String aboie()
|
Source de ClientChien.java
import java.io.*;
import java.net.*;
public class ClientChien {
public static void main(String[] args) throws IOException {
if (args.length != 2) {
System.out.println("Usage : java ClientChien hostName nom_chien" );
System.exit(1);
}
String hostName = args[0];
String chienDemandé = args[1];
Socket sock = null;
PrintWriter sockOut = null;
ObjectInputStream sockIn = null;
try {
sock = new Socket(hostName, 7777);
sockOut = new PrintWriter(sock.getOutputStream(), true);
sockIn = new ObjectInputStream(sock.getInputStream());
} catch (UnknownHostException e) {
System.err.println("host non atteignable : "+hostName);
System.exit(1);
} catch (IOException e) {
System.err.println("connection impossible avec : "+hostName);
System.exit(1);
}
sockOut.println(chienDemandé);
try {
Object recu = sockIn.readObject();
if (recu == null)
System.out.println("erreur de connection");
else if (recu.getClass().equals(Chien5.class)) {
Chien5 chien = (Chien5)recu;
System.out.println("recu: " + chien);
}
} catch (ClassNotFoundException e) {
System.err.println("Classe inconnue : "+hostName);
System.exit(1);
}
sockOut.close();
sockIn.close();
sock.close();
}
}
|
Source de ServerChien.java
import java.net.*;
import java.io.*;
class ServerChien {
public static void main(String args[]) {
Chien5[] tabChien = {
new Chien5("medor", "wouf", 3),
new Chien5("milou", "wouah", 0),
new Chien5("cerbere", "grrr", 12)
};
ServerSocket server = null;
try {
server = new ServerSocket(7777);
while (true) {
Socket sock = server.accept();
System.out.println("accept");
ObjectOutputStream sockOut =
new ObjectOutputStream(sock.getOutputStream());
BufferedReader sockIn = new BufferedReader(
new InputStreamReader(sock.getInputStream()));
String recu;
while ((recu = sockIn.readLine()) != null) {
System.out.println("recu :"+recu);
String nom = recu.trim();
for (int i=0; i<tabChien.length; i++)
if (tabChien[i].getNom().equals(nom)) {
sockOut.writeObject(tabChien[i]);
break;
}
}
sockOut.close();
sock.close();
}
} catch (IOException e) {
System.out.println(e.getMessage());
try {
server.close();
} catch (IOException e2) {
System.out.println(e2.getMessage());
}
}
}
}
|
EXECUTION avec 2 terminaux
$ javac Chien5.java
$ javac ServerChien.java
$ java ServerChien
accept
recu : milou
|
$ javac ClientChien.java
$ java ClientChien localhost milou
recu: chien : milou aboie wouah et a 0 puces.
|
Les lignes de la classe :
- La transmission utilise la sérialisation
:
- Tout objet JAVA peut être sauvegardé
sous forme d'une séquence d'octets et restauré.
- Donc transmis au travers du réseau
- d'où RMI
++ Ecriture ou lecture
sur socket fermé
source de ServerTestSocket :
import java.net.*;
import java.io.*;
import java.util.*;
class ServerTestSocket {
public static void main(String args[]) {
ServerSocket server = null;
Socket sock = null;
OutputStream sockOut = null;
try {
server = new ServerSocket(7777);
} catch (IOException e1) {
System.out.println("impossible creer server : "+e1.getMessage());
}
System.out.println("server ecoute sur port 7777");
Scanner scan = new Scanner(System.in);
String message = "";
message = scan.next().trim().toLowerCase();
while (! message.equals("quit")) {
try {
sock = server.accept();
} catch (IOException e2) {
System.out.println("server accept erreur : "+e2.getMessage());
System.exit(1);
}
try {
sockOut = sock.getOutputStream();
} catch (IOException e6) {
System.out.println("server sock.getOutputStream() erreur : "
+e6.getMessage());
System.exit(1);
}
System.out.println("server accept connection d'un client");
byte[] buffer = new byte[1024];
while ((! message.equals("quit"))&&(! message.equals("close"))) {
buffer = message.getBytes();
try {
sockOut.write(buffer,0,message.length());
sockOut.flush();
} catch (IOException e3) {
System.out.println("server write error :(fermeture du client?)"
+e3.getMessage());
}
message = scan.next().trim().toLowerCase();
}
if ( message.equals("close"))
try {
sockOut.close();
sock.close();
message = scan.next().trim().toLowerCase();
} catch (IOException e5) {
System.out.println("server sockOut ou sock close erreur : "
+e5.getMessage());
System.exit(1);
}
}
try {
server.close();
} catch (IOException e4) {
System.out.println(e4.getMessage());
}
}
}
|
Les lignes de la classe :
- le server attend des ordres au Clavier
- "close", alors le server ferme
sa connection avec le client en cours
- "quit", alors le server ferme
son service
- autre alors c'est un message à
envoyer au client
- si le client ne lit plus, le server attend
la connection d'un autre client
source de ClientTestSocket :
import java.io.*;
import java.net.*;
import java.util.*;
public class ClientTestSocket {
public static void main(String[] args) {
Socket sock = null;
InputStream sockIn = null;
String hote = "localhost";
if (args.length > 1) {
System.out.println("usage : ClientTestSocket [hote]");
System.exit(1);
} else if (args.length == 1)
hote = args[0];
try {
sock = new Socket(hote, 7777);
sockIn = sock.getInputStream();
} catch (UnknownHostException e) {
System.err.println(hote + " : host non atteignable");
System.exit(1);
} catch (IOException e) {
System.err.println("connection impossible");
System.exit(1);
}
System.out.println("client connecte a hote :"+hote);
Scanner scan = new Scanner(System.in);
String message = scan.next();
message = message.trim().toLowerCase();
while ( message.equals("read")) {
byte[] buffer = new byte[1024];
int lu=0;
try {
lu = sockIn.read(buffer);
} catch (IOException e3) {
System.out.println("erreur sockIn.readLine() :"
+e3.getMessage());
}
if (lu == -1)
System.out.println("fin de flot : recu -1");
else {
Scanner scan2 = new Scanner(new String(buffer));
while (scan2.hasNext())
System.out.println("client recu : "+scan2.next());
}
message = scan.next().trim().toLowerCase();
}
if (message.equals("close")) {
try {
sockIn.close();
} catch (IOException e4) {
System.out.println("erreur sockIn.close() :"
+e4.getMessage());
}
try {
sock.close();
} catch (IOException e5) {
System.out.println("erreur sock.close() :"
+e5.getMessage());
}
}
while (! message.equals("quit"))
message = scan.next().trim().toLowerCase();
}
}
|
Les lignes de la classe :
- le client se connecte au serveur et attend
des ordres au Clavier
- "read", alors le client lit
le flot provenant du serveur
- "close", alors le client ferme
sa connection avec le server en cours
- "quit", alors le client quitte
EXECUTION
$ java ServerTestSocket
server ecoute sur port 7777
coucou
server accept connection d'un client
|
$ java ClientTestSocket
client connecte a hote :localhost
read
client recu : coucou
close
quit
$
|
encore
unautre
server write error : (fermeture du client ?)Broken pipe
quit
|
EXECUTION
$ java ServerTestSocket
server ecoute sur port 7777
coucou
server accept connection d'un client
|
$ java ClientTestSocket
client connecte a hote :localhost
read
client recu : coucou
|
read
fin de flot : recu -1
|
exercices
- Ecrire un programme client pour notre
serveur HTTP "simplet" : protocol simplifié à l'extrême
!
- le service est lancé en spécifiant
un port d'écoute dans une console
$ java MonSimpleServeurHttp
8000
- le client ne peut effectuée qu'une
requête "GET [chemin/]fichier"
- le serveur renvoie une réponse
d'erreur si la requête est erronée ou le fichier
demandée inaccessible
- le serveur ne sert qu'un client à
la fois
- il n'y a aucune sécurité
coté serveur de restriction d'accès aux fichiers
: la requete peut concerner /etc/passwd
- une fois le contenu du fichier fourni,
le serveur ferme la connection comme dans la version 1.0 du protocol
HTTP
- Avant d'écrire ce client, vous pouvez faire un test du service avec telnet :
on suppose que le service fonctionne ...
$ telnet -e$ localhost 8000
GET Chien5.java
HTTP/1.0 200 OK
....
Correction