📄 chatserver.java
字号:
package fr.iutvalence.java.tp8.chat.server;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.nio.charset.Charset;
import fr.iutvalence.java.tp8.chat.server.exceptions.InformationAccessException;
import fr.iutvalence.java.tp8.chat.server.exceptions.UnknownUserException;
/**
* Exercice d'application sur l'utilisation de JDBC (TP8).<br/> Partie serveur
* de l'application de chat, attente et validation des connexions. <br/><br/>
*
* Commentaires à sebastien.jean@iut-valence.fr
*
* @author Sébastien JEAN, IUT Valence, oct. 2006
* @version 1.0
*/
public class ChatServer
{
/**
* Le couple (IP,port) auquel le serveur doit s'attacher (bind).
*/
private InetSocketAddress address;
/**
* Le socket de bienvenue.
*/
private ServerSocket serverSocket;
/**
* Le distributeur de messages associé au serveur.
*/
private ChatServerDispatcher dispatcher;
/**
* Le gestionnaire d'informations utilisateurs associé au serveur.
*/
private UsersInfoManager infoManager;
/**
* Constructeur avec paramètre. Initialisation d'un serveur avec attachement
* local donné.
*
* @param a le couple (IP,port) auquel le serveur doit s'attacher.
* @param manager le gestionnaire d'informations utilisateurs associé au
* serveur.
*/
public ChatServer(InetSocketAddress a, UsersInfoManager manager)
{
// Initialisation de l'adresse de niveau transport associée au serveur
this.address = a;
// Initialisation du gestionnaires d'informations utilisateurs
this.infoManager = manager;
// Création et démarrage d'un nouveau distributeur de messages
this.dispatcher = new ChatServerDispatcher();
this.dispatcher.start();
}
/**
* Méthode interne utilisée pour initialiser le socket de bienvenue
* (création + bind).
*
* @throws IOException si l'initialisation du socket serveur échoue.
*/
private void initServerSocket() throws IOException
{
// Création du socket serveur
this.serverSocket = new ServerSocket();
// Attachement local du serveur au couple (IP,port)
this.serverSocket.bind(this.address);
}
/**
* Méthode interne utilisée pour fermer un socket (typiquement le socket
* client).
*
* @param s le socket à fermer.
*/
private void closeSocket(Socket s)
{
try
{
s.close();
}
catch (IOException f)
{}
}
/**
* Méthode interne gérant l'établissement de la connexion
*
* @param s le socket permettant la communication avec le client se
* connectant.
* @return le pseudonyme du client connecté si la connexion est acceptée,
* <tt>null</tt> sinon.
* @throws IOException si la communication échoue.
* @throws InformationAccessException si l'accès aux informations
* utilisateurs échoue.
*/
private String acceptUser(Socket s) throws IOException,
InformationAccessException
{
String pseudo = null;
// Envoi d'une demande d'identification au client
// (il s'agit de lui envoyer une chaîne de caractères UTF-8
// exprimant qu'il doit saisir son pseudonyme)
// Il faut donc écrire une ligne de texte UTF-8 sur le socket, en
// utilisant une chaîne de flots constituée d'un
// PrintStream écrivant des caractères UTF-8 à travers le flot
// d'écriture binaire associé au socket
PrintStream ps = new PrintStream(s.getOutputStream(), true, "UTF-8");
ps.println("Bienvenue ! Entrez votre pseudo "
+ "(chaîne de caractères terminée"
+ " par un retour à la ligne)");
// Lecture du pseudo du client (ligne de texte UTF-8)
// Pour lire une ligne de texte UTF-8 sur le socket,
// il faut utiliser une chaîne de flots constituée d'un
// BufferedReader lisant des lignes de texte à travers un
// InputStreamReader lisant des caractères UTF-8 à travers le flot
// de lecture binaire associé au socket
BufferedReader br = new BufferedReader(new InputStreamReader(s
.getInputStream(), "UTF-8"));
pseudo = br.readLine();
if (pseudo == null)
throw new IOException();
// Envoi d'une demande d'authentification au client
// (il s'agit de lui envoyer une chaîne de caractères UTF-8
// exprimant qu'il doit saisir son mot de passe)
ps.println("Entrez votre mot de passe "
+ "(chaîne de caractères terminée"
+ " par un retour à la ligne)");
// Lecture du mot de passe du client (ligne de texte UTF-8)
String pass = br.readLine();
if (pass == null)
throw new IOException();
// Vérification des informations d'authentification et de l'état de
// connexion du client en utilisant le gestionnaire d'informations
// utilisateurs. Un refus de connexion est notifié au client le cas
// échéant
try
{
if (!(pass.trim().equals(this.infoManager.getPassword(pseudo))))
{
ps.println("Mot de passe erroné, connexion refusée.");
return null;
}
if (this.infoManager.getConnectionState(pseudo))
{
ps.println("Client, déjà connecté, connexion refusée.");
return null;
}
}
catch (UnknownUserException e1)
{
// Envoi d'une notification de refus de connexion au client
ps.println("Pseudonyme inconnu, connexion refusée.");
return null;
}
// Enregistrement d'un nouveau client auprès du distributeur de
// messages
// remarque : ici, on est sûr que l'association ne contient pas déjà
// une entrée correspondant au client.
this.dispatcher.addClient(pseudo, s);
// Mise à jour de l'état de connexion du client (et de l'état "away")
try
{
this.infoManager.setConnectionState(pseudo, true);
this.infoManager.setAwayState(pseudo, false);
}
catch (Exception e)
{
// Remarque : les 2 exceptions possibles
// UnknownUserException et NotConnectedException
// ne peuvent pas survenir
}
// Envoi au client d'un message de bienvenue indiquant également le
// nombre d'utilisateurs connectés
String welcome = "ChatServer> Bienvenue " + pseudo + " !\n";
int connectes = this.dispatcher.getClientCount();
welcome += "ChatServer> " + connectes;
if (connectes > 1)
{
welcome += " utilisateurs connectés";
}
else
{
welcome += " utilisateur connecté";
}
ps.println(welcome);
return pseudo;
}
/**
* Démarrage du serveur.
*/
public void start()
{
// Vérification du support du jeu de caractères UTF-8 sur la plateforme
if (!(Charset.availableCharsets().containsKey("UTF-8")))
{
System.err.println("<ChatServer> Le jeu de caractères UTF-8 "
+ "n'est pas supporté par la platforme");
return;
}
// Initialisation du socket serveur
try
{
this.initServerSocket();
}
catch (IOException e)
{
System.err
.println("<ChatServer> Démarrage du serveur "
+ "impossible : problème lors de l'initialisation du socket serveur");
// Fermeture du socket de bienvenue
try
{
this.serverSocket.close();
}
catch (IOException e1)
{}
System.out.println("<ChatServer> Arrêt du serveur");
return;
}
System.out.println("<ChatServer> Serveur démarré>");
while (true)
{
Socket s = null;
try
{
// Attente bloquante d'une connexion
s = this.serverSocket.accept();
}
catch (IOException e)
{
// Si une erreur se produit, on termine le serveur
System.err.println("<ChatServer> Echec lors de la connexion"
+ " d'un client");
break;
}
// Dialogue initial avec le client pour valider la connection
String pseudo;
try
{
pseudo = this.acceptUser(s);
if (pseudo == null)
throw new IOException();
}
catch (IOException e)
{
System.err
.println("<ChatServer> Connexion avec le client interrompue !");
this.closeSocket(s);
continue;
}
catch (InformationAccessException e)
{
System.err
.println("<ChatServer> Accès aux informations utilisateurs impossible !");
break;
}
// Affichage dans la console du serveur du pseudo,
// de l'adresse IP et du port associés au client
System.out.println("<ChatServer>" + pseudo + " connecté depuis "
+ s.getRemoteSocketAddress().toString());
// Lancement d'une nouvelle tâche pour la gestion de la
// communication avec ce client
new ChatServerThread(pseudo, s, this.dispatcher, this.infoManager)
.start();
}
// Fermeture du socket serveur
try
{
this.serverSocket.close();
}
catch (IOException e)
{}
System.out.println("<ChatServer> Arrêt du serveur");
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -