Examen de Java
Correction
FIUPSO 3/DESS – Ann´ee 2001/2002
Hugues MOUNIER
1 f´evrier 2002
Modalit´es
– Dur´ee : 4 heures
– Tous les documents sont autoris´es.
– Les sources java r´epondant `a chaque exercice, et seulement les sources seront obli-
gatoirement copi´es dans le r´epertoire examenjava (tout en minuscules) cr´ee `a la
racine de votre compte.
Solution de l’ex. 1 Calculatrice
Voici une solution possible :
// Gestion simpliste de banque utilisant des sockets
import java.util.*;
import java.io.*;
public class Calculette {
static double resultat = 0;
/ methodes /
static int somme(int a, int b) { return(a+b); }
static int soustraction(int a, int b) { return(a-b); }
static int multiplication(int a, int b) { return(a*b); }
static double division(int a, int b) { return(a/b); }
public static void main(String args[]) {
BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
// Boucle infinie
for(;;) {
try {
// Afficher une invite a l’utilisateur
System.out.println("1 Somme de deux entiers\n" +
"2 Soustraction de deux entiers\n" +
"3 Multiplication de deux entiers\n" +
"4 Division de deux entiers\n" +
"5 Sortie du programme\n\n" +
"Veuillez entrer votre choix :\n");
// Lire une ligne entree par l’utilisateur
String line = in.readLine();
1
Examen Java
FIUPSO 3/DESS
2001/2002
entre "quit", on sort
// Si l’on rencontre une fin de fichier, ou si l’utilisateur
//
if ((line == null) || line.equals("5")) break;
// On essaie de formatter l’entree de l’utilisateur,
int choix = Integer.parseInt(line);
System.out.print("Veuillez entrer le 1er entier : ");
line = in.readLine();
int x = Integer.parseInt(line);
System.out.print("Veuillez entrer le 2eme entier : ");
line = in.readLine();
int y = Integer.parseInt(line);
switch(choix) {
case 1 : resultat = somme(x, y); // Somme
case 2 : resultat = soustraction(x, y); // Soustraction
break;
break;
case 3 : resultat = multiplication(x, y); // Multiplication
case 4 : resultat = division(x, y); // Division
break;
}
System.out.println("Resultat : " + resultat);
break;
}
// Affichage d’un message d’erreur en cas de probleme
catch(Exception e) { System.out.println("Entree Invalide"); }
}
}
}
Gestion de banque en client/serveur par sockets
L’objet des exercices qui suivent est de d´evelopper une application de gestion bancaire
simple en r´eseau, utilisant les sockets. Ce dernier m´ecanisme n’offrant que du transfert de
flux, donc d’assez bas niveau, il est n´ecessaire de concevoir un protocole permettant de
diff´erentier les diff´erentes op´erations bancaires tout en acheminant les donn´ees pertinentes.
Ce type de conception ne serait pas n´ecessaire si l’on prenait des invocations de m´ethodes
distantes (RMI), bien que l’on perde ´evidemment en souplesse de conception.
Pour r´ealiser l’objectif vis´e, on se fondera sur l’exercice de gestion bancaire en local. On
repr´esentera un paquet par une classe d´ecrite ci-dessous.
Solution de l’ex. 2 Paquets `a ´echanger
Une solution possible est la suivante :
// Gestion simpliste de banque utilisant des sockets
import java.util.*;
import java.io.*;
/**
- Classe pour stocker les donnees d’un compte bancaire
**/
class Account {
String password;
int
Vector transactions = new Vector();
balance;
// mot de passe
// solde du compte
// historique des transactions
Hugues MOUNIER
2
Examen Java
FIUPSO 3/DESS
2001/2002
Account(String password) {
this.password = password;
this.balance = 0;
transactions.addElement("Compte ouvert le " + new Date());
}
}
/**
- Classe representant un paquet du protocoloe bancaire
**/
public class BankSocketPacket {
String
int
String
int
name;
operation;
password;
amount;
// nom du compte
// operation bancaire
// mot de passe
// solde
/ Operations /
public static final int OPEN
public static final int CLOSE
public static final int DEPOSIT
public static final int WITHDRAW
public static final int BALANCE
public static final int QUIT
/ Erreurs /
public static final int TRANSOK
public static final int EXISTANT
public static final int NONEXISTANT = -2; // Operation sur compte inexistant
public static final int INVPASSWORD = -3; // Mot de passe invalide
public static final int NEGBALANCE
// Ouverture de compte
// Fermeture de compte
// Depot sur un compte
// Retrait sur un compte
// Solde d’un compte
// Sortie du programme
= 0;
= -1; // Overture de compte deja existant
= -4; // Solde insuffisant pour retrait
= 1;
= 2;
= 3;
Publicité
= 4;
= 5;
= 6;
// Transaction bien passee
BankSocketPacket(String theName, int theOperation,
String thePassword, int theAmount) {
= theName;
name
operation = theOperation;
password = thePassword;
amount
= theAmount;
}
public String foldPacket() {
String
StringBuffer
foldedPacket;
tobeFolded = new StringBuffer();
tobeFolded.append(this.name).append(":");
Integer opCode = new Integer(this.operation);
tobeFolded.append(opCode.toString());
if (password != null) {
tobeFolded.append(":").append(this.password);
}
}
tobeFolded.append(":").append(this.amount);
tobeFolded.append("#");
foldedPacket = new String(tobeFolded);
return(foldedPacket);
public void unfoldPacket(String foldedPacket) {
Hugues MOUNIER
3
Examen Java
FIUPSO 3/DESS
2001/2002
String
unfoldedTab[] = new String[4];
/ Le deballage est d’abord effectue dans un tableau de String /
int current = foldedPacket.indexOf(’:’, 0);
int next
int last
int i
= foldedPacket.indexOf(’:’, current+1);
= current;
= 1;
unfoldedTab[0] = foldedPacket.substring(0, current);
while (next != -1) {
unfoldedTab[i++] = foldedPacket.substring(current+1, next);
last
= current;
current = foldedPacket.indexOf(’:’, last+1);
next
= foldedPacket.indexOf(’:’, current+1);
}
unfoldedTab[i] = foldedPacket.substring(current+1, foldedPacket.length()-1);
/ On remplit les champs du paquet deballe /
try {
name = new String(unfoldedTab[0]);
operation = Integer.parseInt(unfoldedTab[1]);
password = new String(unfoldedTab[2]);
amount = Integer.parseInt(unfoldedTab[3]);
} catch (NumberFormatException e) {
System.err.println("Erreur en unfoldPacket()--parseInt() : ");
System.err.println(e);
System.exit(1);
}
}
/ Test /
/*
public static void main(String[] args) {
Account cpte = new Account("issos");
BankSocketPacket packet = new BankSocketPacket("Alexandre", cpte, OPEN);
String aAfficher = packet.foldPacket();
System.out.println(aAfficher);
String[] deballe = BankSocketPacket.unfoldPacket(aAfficher);
for(int i = 0; i < deballe.length; i++)
System.out.println(deballe[i]);
}
*/
}
Solution de l’ex. 3 ´Elaboration du serveur
Une solution possible est la suivante :
// Serveur Bancaire simpliste en sockets
import java.util.*;
import java.io.*;
import java.net.*;
/**
- Cette classe implante les methodes distantes definies par l’interface
- RemoteBank. Son plus gros defaut est que toutes les informations sur les
Hugues MOUNIER
4
Examen Java
FIUPSO 3/DESS
2001/2002
- comptes sont perdues lorsque le serveur s’arrete.
**/
public class BankServerSocket
{
public final static int DEFAULT_PORT = 6789;
Hashtable accounts = new Hashtable();
static int transCode;
/**
- Ouvre un compte avec le nom et le mot de passe specifie
- Cette methode est synchronisee de facon qu’une seule thread
- ne modifie a la fois la table des comptes.
**/
public synchronized void openAccount(String name, String password) {
// Verifier s’il exsite deja un compte ayant ce nom
if (accounts.get(name) != null) {
transCode = BankSocketPacket.EXISTANT;
return;
}
// S’il n’existe pas, le creer
Account acct = new Account(password);
// Et l’enregsitrer
accounts.put(name, acct);
transCode = BankSocketPacket.TRANSOK;
}
/**
- Cette methode utilitaire n’est pas une methode accessible de maniere
- distante. Etant donnes un nom et un mot de passe, verifie s’il existe
- un compte correspondant. Si oui, renvoie l’objet Account. Sinon,
- leve une exception.
**/
public Account verify(String name, String password) {
synchronized(accounts) {
Account acct = (Account)accounts.get(name);
if (acct == null) {
transCode = BankSocketPacket.NONEXISTANT;
return null;
}
if (!password.equals(acct.password)) {
transCode = BankSocketPacket.INVPASSWORD;
return null;
}
transCode = BankSocketPacket.TRANSOK;
return acct;
}
}
/**
- Ferme le compte dont on donne le nom. Methode synchronisee
**/
public synchronized FunnyMoney closeAccount(String name, String password) {
Account acct;
acct = verify(name, password);
if (acct != null) {
accounts.remove(name);
synchronized (acct) {
int balance = acct.balance;
Hugues MOUNIER
5
Examen Java
FIUPSO 3/DESS
Publicité
2001/2002
acct.balance = 0;
return new FunnyMoney(balance);
}
} else
return new FunnyMoney(-1);
}
/* Deposer le montant specifie su le compte dont on donne le nom /
public void deposit(String name, String password, FunnyMoney money) {
Account acct = verify(name, password);
if (acct != null)
synchronized(acct) {
acct.balance += money.amount;
acct.transactions.addElement(money.amount + " pieces deposees le "
+ new Date());
}
}
/* Effectue un retarit d’un montant specifie /
public FunnyMoney withdraw(String name, String password, int amount) {
Account acct = verify(name, password);
if (acct != null)
synchronized(acct) {
if (acct.balance < amount) {
transCode = BankSocketPacket.NEGBALANCE;
return new FunnyMoney(0);
}
acct.balance -= amount;
acct.transactions.addElement("Retrait de " + amount + " le "+new Date());
return new FunnyMoney(amount);
}
else
}
return new FunnyMoney(-1);
/* Renvoie le solde du compte dont on donne le nom /
public int getBalance(String name, String password) {
Account acct = verify(name, password);
if (acct != null)
synchronized(acct) { return acct.balance; }
else
return -1;
}
/**
- Renvoie un vecteur de String contenant l’historique pour
- le compte dont on donne le nom
**/
public Vector getTransactionHistory(String name, String password) {
Account acct = verify(name, password);
synchronized(acct) { return acct.transactions; }
}
void sendPacket(String name, int operation, String password, int amount,
BankSocketPacket toSend = new BankSocketPacket(name, operation, password, amount);
String lineTosend = toSend.foldPacket();
PrintStream out) {
Hugues MOUNIER
6
Examen Java
FIUPSO 3/DESS
2001/2002
out.println(lineTosend);
}
/**
- Serveur bancaire par sockets
**/
public static void main (String[] args) throws IOException {
// no de port du service
int
String
ServerSocket
Socket
DataInputStream in;
PrintStream
out;
port;
lineRecieved = null;
server;
client;
String
int
String
int
FunnyMoney
name;
operation;
password;
amount;
money;
// Tests d’arguments
switch(args.length) {
case 0 : port = DEFAULT_PORT;
break;
case 1 : try {
port = Integer.parseInt (args[0]);
} catch (NumberFormatException e) {
port = DEFAULT_PORT;
}
break;
default :
throw new IllegalArgumentException ("Syntaxe : java BankServerSocket [<port>]");
}
// Creation de socket serveur
System.out.println ("Demarrage sur le port " + port);
server = new ServerSocket (port);
System.out.println ("En ecoute ...");
BankServerSocket bank = new BankServerSocket();
// Boucle generale et service
while (true) {
// Acceptation de connexion
client = server.accept();
System.out.println ("Connexion a " + client.getInetAddress() + " acceptee");
System.out.flush();
// Capture des flux de reception et d’envoi
in = new DataInputStream(client.getInputStream());
out = new PrintStream(client.getOutputStream());
//-----------------------
// TRAITEMENT DU SERVICE
//-----------------------
while (true) {
// lire une ligne
lineRecieved = in.readLine();
if ((lineRecieved == null))
break;
Hugues MOUNIER
7
Examen Java
FIUPSO 3/DESS
2001/2002
BankSocketPacket toUnfold = new BankSocketPacket(null, 0, null, 0);
toUnfold.unfoldPacket(lineRecieved);
= toUnfold.name;
name
operation = toUnfold.operation;
password = toUnfold.password;
amount
= toUnfold.amount;
switch(operation) {
case BankSocketPacket.OPEN :
bank.openAccount(name, password);
bank.sendPacket("noname", transCode, "nopass", 0, out);
break;
case BankSocketPacket.CLOSE :
money = bank.closeAccount(name, password);
bank.sendPacket(name, transCode, password, money.amount, out);
break;
case BankSocketPacket.DEPOSIT :
money = new FunnyMoney(amount);
bank.deposit(name, password, money);
bank.sendPacket(name, transCode, password, money.amount, out);
break;
Publicité
case BankSocketPacket.WITHDRAW :
money = bank.withdraw(name, password, amount);
bank.sendPacket(name, transCode, password, money.amount, out);
break;
case BankSocketPacket.BALANCE :
int amt = bank.getBalance(name, password);
bank.sendPacket(name, transCode, password, amt, out);
break;
case BankSocketPacket.QUIT :
System.out.println ("Fermeture des socket client & serveur");
client.close ();
server.close ();
System.exit(0);
}
}
if (lineRecieved == null) {
// Sortie du service : le client a termine
System.out.println ("Fermeture de socket client");
client.close ();
}
}// while(true)
}/ main() /
}// BankServerSocket
/*
try {
}
catch (Exception e) {
System.err.println(e);
System.err.println("Utilisation : java BankServerSocket");
System.exit(1); // On sort
}
Hugues MOUNIER
8
Examen Java
FIUPSO 3/DESS
2001/2002
*/
Solution de l’ex. 4 ´Elaboration du client
Une solution possible est la suivante :
// Gestion simpliste de banque en sockets : client
// Historique a terminer ??
import java.util.*;
import java.io.*;
import java.net.*;
/**
- Classes conteneur :
- - FunnyMoney
**/
la monnaie utilisee
/**
- Cette classe simple represente un montant monetaire. N’est qu’un emballage
- d’un entier.
**/
class FunnyMoney {
public int amount;
public FunnyMoney(int amount) { this.amount = amount; }
}
/**
- Client simple interagissant avec un serveur
**/
public class BankSocket {
// Variables de classe constantes : port et machine par defaut
public static final int
public static final String DEFAULT_HOST = "localhost";
DEFAULT_PORT = 6789;
// Methode utilitaire de saisie
public static String getName(BufferedReader in) {
String name = null;
try {
System.out.println("Veuillez entrer le nom du compte : ");
name = new String(in.readLine().toLowerCase());
} catch (IOException e) {
System.err.println("Erreur en readLine()");
}
return name;
}
// Methode utilitaire de saisie
public static String getPassword(BufferedReader in) {
String password = null;
try {
System.out.println("Veuillez entrer le mot de passe : ");
Hugues MOUNIER
9
Examen Java
FIUPSO 3/DESS
2001/2002
password = new String(in.readLine().toLowerCase());
} catch (IOException e) {
System.err.println("Erreur en readLine()");
}
return password;
}
// Methode utilitaire de gestion d’erreur
static void treatError(int errorNb) {
switch(errorNb) {
case BankSocketPacket.EXISTANT
:
System.out.println("Le compte existe deja");
break;
case BankSocketPacket.NONEXISTANT :
System.out.println("Compte inexistant");
break;
case BankSocketPacket.INVPASSWORD :
System.out.println("Mot de passe invalide");
break;
case BankSocketPacket.NEGBALANCE
:
System.out.println("Solde insuffisant");
break;
}
}
// Methode utilitaire d’envoi/reception de paquet
static BankSocketPacket sendReceive(BankSocketPacket toSend,
BankSocketPacket unfolded = new BankSocketPacket(null, 0, null, 0);
DataInputStream sin, PrintStream sout, String message) {
String lineTosend = toSend.foldPacket();
sout.println(lineTosend);
try {
String lineRecieved = sin.readLine();
if (lineRecieved != null) {
unfolded.unfoldPacket(lineRecieved);
if (unfolded.operation == BankSocketPacket.TRANSOK)
System.out.println(message);
else
treatError(unfolded.operation);
} else {
}
System.out.println("Serveur arrete ; sortie");
System.exit(1);
} catch (IOException e) {
System.out.println("Erreur en reception de paquet : " +
e.toString());
System.exit(1);
}
return(unfolded);
}
/**
- Programme client
**/
public static void main(String[] args) {
Hugues MOUNIER
10
Examen Java
FIUPSO 3/DESS
2001/2002
try {
port;
= null; // Machine du serveur
String host
Publicité
int
Socket s
= null;
DataInputStream sin = null;
PrintStream sout
= null;
BufferedReader stdin = null;// Flux associe au clavier
// No de port du serveur (no de service)
// Reference a la socket client
// Flux en provenance du serveur
// Flux a destination du serveur
//
BankSocket b = new BankSocket();
// Tests d’arguments
switch(args.length) {
case 0 : host = new String(DEFAULT_HOST);
port = DEFAULT_PORT;
break;
case 1 : host = new String(args[0]);
port = DEFAULT_PORT;
break;
case 2 : host = new String(args[0]);
try {
port = Integer.parseInt (args[1]);
} catch (NumberFormatException e) {
System.err.println("Numero de port invalide. " +
DEFAULT_PORT + " Utilise.");
port = DEFAULT_PORT;
}
break;
default : System.out.println("Nombre d’arguments illegal");
throw new IllegalArgumentException();
}// switch()
s = new Socket(host, port);
// Creer les flux pour lire et ecrire des lignes de texte
// de et vers cette socket.
sin = new DataInputStream(s.getInputStream());
sout = new PrintStream(s.getOutputStream());
System.out.println("Connecte a " + s.getInetAddress()
+ ":"+ s.getPort());
(par defaut le clavier)
// Creer un flux pour lire des lignes de l’entree standard
//
stdin = new BufferedReader(new InputStreamReader(System.in));
String cmd = "nothing";
while(true) {
System.out.println("\nVeuillez entrer une commande : \n" +
(ouverture de compte)\n" +
(cloture de compte)\n" +
"open
"close
"deposit (depot sur le compte)\n" +
"withdraw (retrait sur le compte)\n" +
"balance (solde du compte)\n" +
"quit
(sortie du programme)\n");
// Convertir la commande utilisateur en minuscules
cmd = stdin.readLine().toLowerCase();
// Differentes actions possibles
if (cmd.equals("open")) {
// ouverture de compte
String name = getName(stdin); String password = getPassword(stdin);
BankSocketPacket packet =
Hugues MOUNIER
11
Examen Java
FIUPSO 3/DESS
2001/2002
new BankSocketPacket(name, BankSocketPacket.OPEN, password, 0);
BankSocketPacket unfolded = sendReceive(packet, sin, sout, "Compte ouvert.");
}
else if (cmd.equals("close")) {
String name = getName(stdin);
BankSocketPacket packet =
// fermeture de compte
String password = getPassword(stdin);
new BankSocketPacket(name, BankSocketPacket.CLOSE, password, -1);
BankSocketPacket unfolded = sendReceive(packet, sin, sout, "Solde : ");
System.out.println(unfolded.amount + " pieces rendues.");
System.out.println("Au revoir.");
}
else if (cmd.equals("deposit")) {
String name = getName(stdin);
System.out.println("Veuillez entrer le montant : ");
int amount = Integer.parseInt(stdin.readLine().toLowerCase());
BankSocketPacket packet =
// depot d’argent
String password = getPassword(stdin);
new BankSocketPacket(name, BankSocketPacket.DEPOSIT, password, amount);
BankSocketPacket unfolded = sendReceive(packet, sin, sout, "Depot realise.");
}
else if (cmd.equals("withdraw")) {
// retrait d’argent
String name = getName(stdin); String password = getPassword(stdin);
System.out.println("Veuillez entrer le montant : ");
int amount = Integer.parseInt(stdin.readLine().toLowerCase());
BankSocketPacket packet =
new BankSocketPacket(name, BankSocketPacket.WITHDRAW, password, amount);
BankSocketPacket unfolded = sendReceive(packet, sin, sout, "Retrait realise.");
}
else if (cmd.equals("balance")) {
// solde du compte
String name = getName(stdin); String password = getPassword(stdin);
BankSocketPacket packet =
new BankSocketPacket(name, BankSocketPacket.BALANCE, password, -1);
BankSocketPacket unfolded = sendReceive(packet, sin, sout, "Solde : ");
System.out.println(unfolded.amount + " pieces sur le compte.");
//
//
//
//
}
else if (cmd.equals("history")) {
String name = getName(stdin);
Vector transactions = bank.getTransactionHistory(name, password);
for(int i = 0; i < transactions.size(); i++)
// historique des transactions
String password = getPassword(stdin);
System.out.println(transactions.elementAt(i));
}
else if (cmd.equals("quit")) {
BankSocketPacket packet =
// break
new BankSocketPacket("noname", BankSocketPacket.QUIT, "nopass", -1);
BankSocketPacket unfolded = sendReceive(packet, sin, sout, "Solde : ");
System.out.println("Au revoir\n");
break;
}
else System.out.println("Action inconnue");
}
}// while not quitted
// Exceptions, erreurs de syntaxe, affichage d’utilisation
catch (Exception e) {
System.err.println(e);
System.err.println("Utilisation : java BankLocal");
}
}
}// class Client
Hugues MOUNIER
12
Examen Java
FIUPSO 3/DESS
2001/2002
Hugues MOUNIER
13