Examen de Java Correction

publicité
Examen de Java
Correction
FIUPSO 3/DESS – Année 2001/2002
Hugues M OUNIER
1 février 2002
Modalités
– Durée : 4 heures
– Tous les documents sont autorisés.
– Les sources java répondant à chaque exercice, et seulement les sources seront obligatoirement copiés dans le répertoire examenjava (tout en minuscules) crée à 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
// Si l’on rencontre une fin de fichier, ou si l’utilisateur
//
entre "quit", on sort
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
break;
case 2 : resultat = soustraction(x, y); // Soustraction
break;
case 3 : resultat = multiplication(x, y); // Multiplication
break;
case 4 : resultat = division(x, y); // Division
break;
}
System.out.println("Resultat : " + resultat);
}
// 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évelopper une application de gestion bancaire
simple en réseau, utilisant les sockets. Ce dernier mécanisme n’offrant que du transfert de
flux, donc d’assez bas niveau, il est nécessaire de concevoir un protocole permettant de
différentier les différentes opérations bancaires tout en acheminant les données pertinentes.
Ce type de conception ne serait pas nécessaire si l’on prenait des invocations de méthodes
distantes (RMI), bien que l’on perde évidemment en souplesse de conception.
Pour réaliser l’objectif visé, on se fondera sur l’exercice de gestion bancaire en local. On
représentera un paquet par une classe décrite ci-dessous.
Solution de l’ex. 2 Paquets à échanger
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
**/
class Account {
String password;
//
int
balance;
//
Vector transactions = new Vector();
//
Hugues M OUNIER
bancaire
mot de passe
solde du compte
historique des transactions
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
name;
// nom du compte
int
operation; // operation bancaire
String
password;
// mot de passe
int
amount;
// solde
/* Operations
public static
public static
public static
public static
public static
public static
/* Erreurs */
public static
public static
public static
public static
public static
*/
final
final
final
final
final
final
int
int
int
int
int
int
OPEN
CLOSE
DEPOSIT
WITHDRAW
BALANCE
QUIT
=
=
=
=
=
=
1;
2;
3;
4;
5;
6;
final
final
final
final
final
int
int
int
int
int
TRANSOK
EXISTANT
NONEXISTANT
INVPASSWORD
NEGBALANCE
=
=
=
=
=
0;
-1;
-2;
-3;
-4;
//
//
//
//
//
//
//
//
//
//
//
Ouverture de compte
Fermeture de compte
Depot sur un compte
Retrait sur un compte
Solde d’un compte
Sortie du programme
Transaction bien passee
Overture de compte deja existant
Operation sur compte inexistant
Mot de passe invalide
Solde insuffisant pour retrait
BankSocketPacket(String theName, int theOperation,
String thePassword, int theAmount) {
name
= theName;
operation = theOperation;
password = thePassword;
amount
= theAmount;
}
public String foldPacket() {
String
foldedPacket;
StringBuffer
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 M OUNIER
3
Examen Java
FIUPSO 3/DESS
String
2001/2002
unfoldedTab[] = new String[4];
/* Le deballage est d’abord effectue dans un tableau de String */
int current = foldedPacket.indexOf(’:’, 0);
int next
= foldedPacket.indexOf(’:’, current+1);
int last
= current;
int i
= 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 Élaboration 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 M OUNIER
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
* Cette methode est synchronisee de facon qu’une
* ne modifie a la fois la table des comptes.
**/
public synchronized void openAccount(String name,
// Verifier s’il exsite deja un compte ayant ce
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;
}
specifie
seule thread
String password) {
nom
/**
* 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 M OUNIER
5
Examen Java
FIUPSO 3/DESS
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();
Hugues M OUNIER
6
Examen Java
FIUPSO 3/DESS
2001/2002
out.println(lineTosend);
}
/**
* Serveur bancaire par sockets
**/
public static void main (String[] args) throws IOException {
int
port;
// no de port du service
String
lineRecieved = null;
ServerSocket
server;
Socket
client;
DataInputStream in;
PrintStream
out;
String
name;
int
operation;
String
password;
int
amount;
FunnyMoney
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 M OUNIER
7
Examen Java
FIUPSO 3/DESS
2001/2002
BankSocketPacket toUnfold = new BankSocketPacket(null, 0, null, 0);
toUnfold.unfoldPacket(lineRecieved);
name
= toUnfold.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
break;
case BankSocketPacket.DEPOSIT :
money = new FunnyMoney(amount);
bank.deposit(name, password, money);
bank.sendPacket(name, transCode, password, money.amount
break;
case BankSocketPacket.WITHDRAW :
money = bank.withdraw(name, password, amount);
bank.sendPacket(name, transCode, password, money.amount
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 M OUNIER
8
Examen Java
FIUPSO 3/DESS
2001/2002
*/
Solution de l’ex. 4 Élaboration 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
DEFAULT_PORT = 6789;
public static final String DEFAULT_HOST = "localhost";
// 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 M OUNIER
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,
DataInputStream sin, PrintStream sout, Stri
BankSocketPacket unfolded = new BankSocketPacket(null, 0, null, 0);
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 M OUNIER
10
Examen Java
//
FIUPSO 3/DESS
2001/2002
try {
String host
= null; // Machine du serveur
int
port;
// No de port du serveur (no de service)
Socket s
= null; // Reference a la socket client
DataInputStream sin = null; // Flux en provenance du serveur
PrintStream sout
= null; // Flux a destination du serveur
BufferedReader stdin = null;// Flux associe au clavier
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());
// Creer un flux pour lire des lignes de l’entree standard
//
(par defaut le clavier)
stdin = new BufferedReader(new InputStreamReader(System.in));
String cmd = "nothing";
while(true) {
System.out.println("\nVeuillez entrer une commande : \n" +
"open
(ouverture de compte)\n" +
"close
(cloture de compte)\n" +
"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 M OUNIER
11
Examen Java
FIUPSO 3/DESS
2001/2002
new BankSocketPacket(name, BankSocketPacket.OPEN, password, 0);
BankSocketPacket unfolded = sendReceive(packet, sin, sout, "Compte ouve
//
//
//
//
}
else if (cmd.equals("close")) {
// fermeture de compte
String name = getName(stdin); String password = getPassword(stdin);
BankSocketPacket packet =
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")) {
// depot 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.DEPOSIT, password, amount);
BankSocketPacket unfolded = sendReceive(packet, sin, sout, "Depot reali
}
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 rea
}
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")) {
// historique des transactions
String name = getName(stdin); String password = getPassword(stdin);
Vector transactions = bank.getTransactionHistory(name, password);
for(int i = 0; i < transactions.size(); i++)
System.out.println(transactions.elementAt(i));
}
else if (cmd.equals("quit")) {
// break
BankSocketPacket packet =
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 M OUNIER
12
Examen Java
Hugues M OUNIER
FIUPSO 3/DESS
2001/2002
13
Téléchargement