package serveur;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import common.Conteneur;
import common.Joueur;
import common.Partie;
import common.Point;
import common.TypeConteneur;
import common.misc.Utils;
public class JxoServeur implements Runnable {
/** Nombre maximal de connexion autorisé */
public static final int DEFAULT_MAX_CLIENTS = 10;
// private String password;
private volatile boolean alive = true;
// Le port utilisé par le serveur
private int serverPort;
// Id pour identifier le serveur
private String serverName;
// set maximum connections allowed
private int maxClients = DEFAULT_MAX_CLIENTS;
// the array of clients
// private Vector clients;
// this is the server itself
private ServerSocket server;
// the clients seeker
private Thread seeker;
// this array contains all the listeners linked to this class
// public Vector listeners = new Vector();
private HashMap joueurs;
private GestionnaireServeur gs;
/**
*
* @param args
*/
public static void main(String[] args) {
JxoServeur js = new JxoServeur(7050/* , "passwd" */);
}
/**
*
* @param serverPort
* @param password
*/
public JxoServeur(int serverPort/* , String password */) {
this(serverPort, new Date().toString()/* , password */);
}
/**
*
* @param serverPort
* @param serverName
* @param password
*/
public JxoServeur(int serverPort, String serverName/* , String password */) {
this(serverPort, serverName, /* password, */DEFAULT_MAX_CLIENTS);
}
/**
*
* @param serverPort
* @param serverName
* @param password
* @param maxClients
*/
public JxoServeur(int serverPort, String serverName,/* String password, */
int maxClients) {
// Sauvegarde des paramétres
this.serverPort = serverPort;
this.serverName = serverName;
// this.password = password;
this.maxClients = maxClients;
joueurs = new HashMap();
gs = new GestionnaireServeur(this);
// if I choosed a Vector, it is just to be able to
// increase its size (more difficult with a simple array)
// clients = new Vector(this.maxClients);
// we start the server
startServer();
// paranoia
if (server == null) {
System.err.println("[Server is not running]");
System.exit(1);
}
}
public synchronized void envoyerConteneur(Conteneur c, Socket s)
throws IOException {
BufferedOutputStream out = new BufferedOutputStream(s.getOutputStream());
// On sérialize et on envoie au serveu
byte[] data = Utils.serialize(c);
out.write(data);
out.flush();
}
/**
*
*
* @param pseudoAdversaire
* @param p
*/
public void prevenirAdversaire(String pseudoAdversaire, Point p) {
Conteneur c = new Conteneur(TypeConteneur.POINT, p);
Socket socketAdv = (Socket) joueurs.get(pseudoAdversaire);
try {
this.envoyerConteneur(c, socketAdv);
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* On prévient les clients que la partie peut commencer
*
* @param pseudoJoueur
*/
public synchronized void partieCommence(String pseudoJoueurCroix,
String pseudoJoueurRond) throws IOException {
/*
* Socket sCroix = new Socket( (InetAddress)
* joueurs.get(pseudoJoueurCroix), DEFAULT_PORT); Socket sRond = new
* Socket((InetAddress) joueurs.get(pseudoJoueurRond), DEFAULT_PORT);
*/
//System.out.println("pseudoJoueurCroix = " + pseudoJoueurCroix);
Socket sCroix = (Socket) joueurs.get(pseudoJoueurCroix);
Socket sRond = (Socket) joueurs.get(pseudoJoueurRond);
Conteneur cCroix = new Conteneur(TypeConteneur.PARTIE_PEUT_COMMENCER,
TypeConteneur.CROIX);
Conteneur cRond = new Conteneur(TypeConteneur.PARTIE_PEUT_COMMENCER,
TypeConteneur.ROND);
// System.out.println("cCroix = "+cCroix);
// System.out.println("sCroix = "+sCroix);
envoyerConteneur(cCroix, sCroix);
envoyerConteneur(cRond, sRond);
}
/**
* Start the server.
*/
private void startServer() {
try {
server = new ServerSocket(serverPort);
server.setSoTimeout(1000);
} catch (IOException ioe) {
System.err.println("[Cannot initialize Server]\n" + ioe);
System.exit(1);
}
// we display IP address and port number to ensure
// the server is ours ;-)
try {
InetAddress url = InetAddress.getLocalHost();
System.out.println("[Server is running]\nServer IP: "
+ url.getHostAddress() + "; Server name: "
+ url.getHostName() + "; Server port: " + serverPort);
} catch (UnknownHostException uhe) {
}
startSeeker();
}
/**
* This resolves clients requests. If we have enough clients, we stop the
* thread.
*/
public void run() {
while (alive)
getClient();
}
/**
* This method get a Client from a ServerSocket.
*
* @return true if we managed to get a client
*/
private void getClient() {
Socket client;
try {
// wait for a client to connect on our port
client = server.accept();
if (joueurs.size() == getMaxClients()) {
System.out.println("[Server cannot handle more clients]");
(new PrintWriter(new OutputStreamWriter(client
.getOutputStream()))).println("/kill");
return;
}
new Authorizer(client/* , password */);
// addClient(new CaffeineSocket(this, client, password));
} catch (IOException ioe) {
if (seeker == null)
alive = false;
return;
}
}
/**
* Stop the seeker by killing the thread, close the server socket, free
* memory and exit.
*/
public void stop() {
stop(false);
}
/**
* Stop the seeker by killing the thread, close the server socket, free
* memory and exit.
*
* @param killJMV
* If true, we <code>System.exit(0);</code>
*/
public void stop(boolean killJVM) {
// kill thread
stopSeeker();
Collection clients = joueurs.values();
Iterator it = clients.iterator();
while (it.hasNext()) {
// JxoSocket kill = (JxoSocket) clients.elementAt(i);
Socket kill = (Socket) it.next();
// Envoi au client du message de fin
try {
// BufferedOutputStream bout = new
// BufferedOutputStream(kill.getOutputStream());
Conteneur c = new Conteneur(TypeConteneur.ARRET_SERVEUR,
new String(TypeConteneur.ARRET_SERVEUR));
envoyerConteneur(c, kill);
} catch (IOException ioe) {
ioe.printStackTrace();
}
// kill.getOut().println("/kill");
// kill.close();
}
// kill clients
/*
* for (int i = 0; i < clients.size(); i++) { JxoSocket kill =
* (JxoSocket) clients.elementAt(i); kill.getOut().println("/kill");
* kill.close(); }
*/
// clients.removeAllElements();
// close server
try {
server.close();
} catch (IOException ioe) {
}
if (killJVM)
System.exit(0);
}
/**
* Stop the seeker by killing the thread.
*/
public void stopSeeker() {
seeker = null;
}
/**
* Start the clients seeker.
*/
public void startSeeker() {
seeker = new Thread(this);
seeker.setName("CaffeineServer: " + serverName + ": Client Seeker");
seeker.setPriority(Thread.MIN_PRIORITY);
seeker.start();
}
/**
*
*/
public synchronized void killClient(String pseudo) {
Socket s = (Socket) joueurs.get(pseudo);
joueurs.remove(pseudo);
try {
s.close();
} catch (IOException ioe) {
ioe.printStackTrace();
}
}
/**
* If a class needs to identify a server, it can use its name.
*
* @return The name of the server
*/
public String getName() {
return serverName;
}
/**
*
* @param pseudo
* @param s
*/
public synchronized void ajouterJoueur(String pseudo, Socket s) {
joueurs.put(pseudo, s);
}
/**
* Set the name of the server.
*
* @param name
* The new name of the server
*/
public void setName(String name) {
serverName = name;
}
/**
* Knowing the running port is very useful for exceptions.
*
* @return The port number used by the server
*/
public int getPort() {
return serverPort;
}
/**
* The server has a limited number of clients.
*
* @return The maximum number of clients allowed
*/
public synchronized int getMaxClients() {
return maxClients;
}
/**
* <code>Authorize</code> is a thread which checks password given by
* client. If the password is wrong, the connection is refused.
*/
class Authorizer extends Thread {
private Socket client;
private InputStream in;
private OutputStream out;
private String pseudo;
private String pseudoAdversaire;
public String OK = "OK";
public String KO = "KO";
public String lastChoice;
Partie dernierePartie;
Authorizer(Socket client) {
super();
this.client = client;
// this.pseudo = pseudo;
try {
in = client.getInputStream();
out = client.getOutputStream();
if (in == null || out == null)
return;
/*
* BufferedReader reader = new BufferedReader( new
* InputStreamReader(in)); PrintWriter writer = new PrintWriter(
* new OutputStreamWriter(out), true);
*/
} catch (IOException ioe) {
ioe.printStackTrace();
}
setPriority(MIN_PRIORITY);
this.setName("jXoServeur: ClientManager");
start();
}
public void run() {
if (client == null)
return;
try {
Conteneur c;
BufferedInputStream bin = new BufferedInputStream(in);
while ((c = (Conteneur) Utils.deserialize(bin)) != null) {
// On récupére le message du client
if (c == null) {
System.out.println("Impossible de récupérer le message pour "+pseudo);
}
// Traitement des messages
if (c != null) {
String type = c.getTypeConteneur();
if(type.equals(TypeConteneur.JOUEUR)){
System.out.println("Arrivée d'un nouveau joueur");
}
else{
System.out.println("[SERVEUR] Le client "+pseudo+" a recu un Conteneur de Type "+
type+((pseudoAdversaire!=null)?" de la part de : "+pseudoAdversaire:""));
}
// RECEPTION D'UN JOUEUR
if (type.equals(TypeConteneur.JOUEUR)) {//ARRIVE D'UN NOUVEAU JOUEUR
Joueur j = (Joueur) c.getObject();
String pseudoCl = j.getPseudo();
if (joueurs.containsKey(pseudoCl)) {
// On prévient le client que ce pseudo est déja
// utilisé
//System.out.println("[SERVEUR] : "+pseudoCl+" Pseudo existant");
c = new Conteneur(
TypeConteneur.PSEUDO_EXISTANT, null);
envoyerConteneur(c, client);
return;
}
// On ajout ce client dans la liste des joueurs du
// serveur
ajouterJoueur(pseudoCl, client);
// On conserve son pseudo
this.pseudo = pseudoCl;
/*System.out.println("[Serveur] : Arrivée de => "
+ pseudo);*/
// On appelle le gestionnaire de connexion
dernierePartie = gs.ajouterJoueur(pseudo);
}else if(type.equals(TypeConteneur.RESTER)){//RESTER APRES DEPART DE L'ADVERSAIRE
dernierePartie = gs.ajouterJoueur(pseudo);
pseudoAdversaire = null;
}else if (type.equals(TypeConteneur.POINT)) {// RECEPTION D'UN POINT
// On récupére le pseudo du joueur associé à cet
// socket
// String pseudo =
// c.getPseudo();//(String)joueurs.get(client);
if (pseudo == null) {
return;
}
Point point = (Point) c.getObject();
// Création de la partie si elle n'existe pas
if (dernierePartie == null) {
dernierePartie = gs.aJouer(pseudo, point);
}
if (dernierePartie != null) {
if (pseudoAdversaire == null) {
pseudoAdversaire = dernierePartie
.getAdversaire(pseudo);
// System.out.println("[SERVEUR] Adversaire de "+pseudo+ " = "+pseudoAdversaire);
}
dernierePartie = gs.aJouer(dernierePartie, point);
boolean aGagne = dernierePartie
.aGagne(dernierePartie
.getSymbole(pseudo));
boolean matchNul = dernierePartie.matchNul();
//System.out.println("aGagné = "+aGagne);
Socket socketAdversaire = (Socket) joueurs
.get(pseudoAdversaire);
Conteneur cAdversaire = null;
Conteneur cMatchNul = new Conteneur(TypeConteneur.MATCH_NUL,null);
if (aGagne) { // VICTOIRE DE CE CLIENT
// L'adversaire a perdu, on lui envoit le
// point et le résultat de la partie
// On envoit le résultat au gagnant
// également
// On termine la partie
cAdversaire = new Conteneur(
TypeConteneur.PERDU, point);
Conteneur cGagnant = new Conteneur(
TypeConteneur.GAGNE, null);
envoyerConteneur(cGagnant, client);
} else if(matchNul){ // MATCH NUL
envoyerConteneur(cMatchNul, client);
cAdversaire = cMatchNul;
}else { // PERDU
System.out.println("CAS INEXISTANT ");
// On Envoie seulement le point à
// l'adversaire
cAdversaire = new Conteneur(
TypeConteneur.POINT, point);
}
// On envoie les conteneurs apropriés à chacun des joueurs
if (socketAdversaire != null
&& cAdversaire != null) {
envoyerConteneur(cAdversaire,
socketAdversaire);
}
}
}else if( (type.equals(TypeConteneur.REJOUER_OK)) ||
(type.equals(TypeConteneur.REJOUER_KO)) ){
// On remet à zero la partie et on peut y aller
//dernierePartie = gs.remettreAZeroPartie(dernierePartie);
dernierePartie = gs.getPartie(dernierePartie);
if(dernierePartie == null){
//System.out.println("Plus de partie, l'autre est parti !");
}else{
if(type.equals(TypeConteneur.REJOUER_OK)){
dernierePartie.addOk();
lastChoice = OK;
System.out.println("[SERVEUR] => Je veux rejouer = "+dernierePartie.getNbOk());
}else if(type.equals(TypeConteneur.REJOUER_KO)){
dernierePartie.addKo();
lastChoice = KO;
}
//On remet à jour la partie sur le gestionnaire
//gs.putPartie(dernierePartie);
if(dernierePartie.getKoAndOk() == 2){
// Fin de partie
Socket socketAdversaire = (Socket) joueurs
.get(pseudoAdversaire);
if(dernierePartie.getNbOk() == 2){
// On remet à jour la partie sur le gestionnaire
//System.out.println("Deux ok !");
Conteneur conteneur = new Conteneur(TypeConteneur.REJOUER_OK,null);
//Message pour rejouer au 2
envoyerConteneur(conteneur,client);
envoyerConteneur(conteneur,socketAdversaire);
}else{
// On ne rejoue pas
if(lastChoice.equals(OK)){
Conteneur conteneur = new Conteneur(TypeConteneur.ATTENTE,null);
//System.out.println("[SERVEUR] "+pseudo+" ATTENTE !");
//On arrete la partie
gs.arreterPartie(dernierePartie);
dernierePartie = gs.ajouterJoueur(pseudo);
pseudoAdversaire = null;
//Message pour rejouer au 2
envoyerConteneur(conteneur,client);
}else{
Conteneur conteneur = new Conteneur(TypeConteneur.REJOUER_KO,null);
//Message de fin
envoyerConteneur(conteneur,socketAdversaire);
}
}
// On arrete la partie
dernierePartie.remettreAZero();
dernierePartie.initKoAndOk();
}
//On remet à jour la partie sur le gestionnaire
gs.putPartie(dernierePartie);
}
}
}
}
} catch (ClassNotFoundException cnf) {
// cnf.printStackTrace();
System.out.println(cnf);
} catch (NullPointerException npe) {
// npe.printStackTrace();
//System.out.println(npe);
npe.printStackTrace();
} catch (IOException ioe) {
System.out.println(pseudo + " s'est deconnecté ");
if (pseudoAdversaire != null) {
Socket socketAdversaire = (Socket) joueurs
.get(pseudoAdversaire);
Conteneur cAdversaire = new Conteneur(
TypeConteneur.DECO_ADVERSAIRE, null);
try {
//On regarde si l'adversair existe encore
if(socketAdversaire != null){
gs.arreterPartie(dernierePartie);
envoyerConteneur(cAdversaire, socketAdversaire);
}
} catch (IOException ioe2) {
ioe2.getMessage();
ioe2.printStackTrace();
}
}else{
// Pas d'adversaire, on retire le joueur qui vient de se déconnectet de la partie en attente
System.out.println("[SERVEUR] Plus de joueur en attente !");
gs.retirerJoueurEnAttente();
}
if(dernierePartie != null){
//System.out.println("Départ de "+pseudo+", la partie est Finie");
// On demande au gestionnaire de terminer la partie
gs.finPartie(dernierePartie);
}
// On prévient le serveur de son départ
killClient(pseudo);
// ioe.printStackTrace();
}
}
}
}