📄 chatserverthread.java
字号:
package fr.iutvalence.java.tp8.chat.server;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.Socket;
import fr.iutvalence.java.tp8.chat.server.exceptions.InformationAccessException;
/**
* Exercice d'application sur l'utilisation de JDBC (TP8).<br/> Thread
* serveur de l'application de chat, gérant la communication avec un client
* (i.e. réception et traitement des messages émis par le client). <br/><br/>
*
* Commentaires à sebastien.jean@iut-valence.fr
*
* @author Sébastien JEAN, IUT Valence, oct. 2006
* @version 1.0
*/
public class ChatServerThread extends Thread
{
/**
* Le socket utilisé pour la communication avec le client.
*/
private Socket socket;
/**
* Le distributeur de messages associé au serveur.
*/
private ChatServerDispatcher dispatcher;
/**
* Le gestionnaire d'informations utilisateurs associé au serveur.
*/
private UsersInfoManager infoManager;
/**
* Constructeur avec paramètres. Initialisation d'un thread serveur
* communicant avec un client donné.
*
* @param pseudo le pseudonyme du client = le nom du thread.
* @param sock le socket permettant la communication avec le client.
* @param disp le distributeur de messages associé au serveur.
* @param manager le gestionnaire d'informations utilisateurs associé au
* serveur.
*/
public ChatServerThread(String pseudo, Socket sock,
ChatServerDispatcher disp, UsersInfoManager manager)
{
super(pseudo);
// Passage de la tâche en démon pour ne pas empécher l'arrêt propre du
// serveur
this.setDaemon(true);
// Initialisation du socket et du distributeur
this.socket = sock;
this.dispatcher = disp;
this.infoManager = manager;
}
/**
* Affichage d'un message sur la console du serveur et terminaison de la
* tâche.
*
* @param s le message à afficher sur la console du serveur.
*/
private void end(String s)
{
if (s != null)
{
System.out.println(s);
}
try
{
this.socket.close();
}
catch (IOException e)
{}
// Désenregistrement du client
this.dispatcher.removeClient(this.getName());
// Mise à jour de l'état de connexion du client (et de l'état "away")
try
{
this.infoManager.setConnectionState(this.getName(), false);
this.infoManager.setAwayState(this.getName(), false);
}
catch (Exception e)
{
// Remarque : les 2 exceptions possibles
// UnknownUserException et NotConnectedException
// ne peuvent pas survenir
}
}
/**
* Méthode interne gérant le traitement des messages reçus
*
* @param message le message reçu du client.
* @throws InformationAccessException si l'accès aux informations
* utilisateurs a échoué.
*/
private void processMessage(String message)
throws InformationAccessException
{
// Si message privé, envoi en unicast via le distributeur de messages
if (message.startsWith("#TELL "))
{
String tellParams = message.substring(6).trim();
int indexEndPseudo = tellParams.indexOf(' ');
String tellPseudo = tellParams.substring(0, indexEndPseudo);
String tellMessage = tellParams.substring(indexEndPseudo).trim();
this.dispatcher.unicastMessage(this.getName(), tellPseudo,
tellMessage);
return;
}
// Si notification d'absence, mise à jour des informations utilisateurs
// et envoi d'un message d'avertissement en diffusion
if (message.startsWith("#AWAY"))
{
try
{
// Si le client s'est déjà déclaré absent, le message est sans
// effet
boolean hasEffect = false;
synchronized (this.infoManager)
{
if (!this.infoManager.getAwayState(this.getName()))
{
this.infoManager.setAwayState(this.getName(), true);
hasEffect = true;
}
}
if (hasEffect)
this.dispatcher.broadCastMessage("ChatServer", this
.getName()
+ " s'absente");
}
catch (Exception e)
{
// Remarque : les 2 exceptions possibles
// UnknownUserException et NotConnectedException
// ne peuvent pas survenir
}
return;
}
// Si notification de retour, mise à jour des informations utilisateurs
// et envoi d'un message d'avertissement en diffusion
if (message.startsWith("#BACK"))
{
try
{
// Si le client n'est pas déclaré absent, le message est sans
// effet
boolean hasEffect = false;
synchronized (this.infoManager)
{
if (this.infoManager.getAwayState(this.getName()))
{
this.infoManager.setAwayState(this.getName(), false);
hasEffect = true;
}
}
if (hasEffect)
this.dispatcher.broadCastMessage("ChatServer", this
.getName()
+ " est de retour");
}
catch (Exception e)
{
// Remarque : les 2 exceptions possibles
// UnknownUserException et NotConnectedException
// ne peuvent pas survenir
}
return;
}
// Sinon (message en diffusion), envoi en diffusion via le distributeur
// de messages
this.dispatcher.broadCastMessage(this.getName(), message);
}
/**
* Corps de la tâche.
*/
public void run()
{
// Obtention d'un flot de lecture de lignes de texte UTF-8 sur le socket
BufferedReader br = null;
try
{
InputStream is = this.socket.getInputStream();
InputStreamReader isr = new InputStreamReader(is);
br = new BufferedReader(isr);
}
catch (IOException e)
{
this.end("<ChatServer> [" + this.getName() + "] problème d'IO, "
+ "fermeture de la connexion");
return;
}
// Diffusion d'un message d'alerte aux autres clients
this.dispatcher.broadCastMessage("ChatServer", this.getName()
+ " connecté");
// Boucle réception/diffusion tant que la connexion reste établie
while (true)
{
// Attente bloquante de la réception d'un message à diffuser
String message = null;
try
{
message = br.readLine();
if (message == null)
throw new IOException();
}
catch (IOException e)
{
this.dispatcher.broadCastMessage("ChatServer", this.getName()
+ " déconnecté");
this.end("<ChatServer> [" + this.getName() + "] "
+ this.getName() + " déconnecté");
return;
}
// Traitement du message
try
{
this.processMessage(message);
}
catch (InformationAccessException e)
{
System.err.println("<ChatServer> [" + this.getName()
+ "] accès aux informations utilisateurs "
+ "impossible, le message spécial n'a pas été traité");
}
}
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -