📄 chatserverdispatcher.java
字号:
package fr.iutvalence.java.tp8.chat.server;
import java.io.PrintStream;
import java.net.Socket;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
/**
* Exercice d'application sur l'utilisation de JDBC (TP8).<br/> Distributeur de
* messages à un ensemble de clients enregistrés. Version étendue par rapport à
* celle du TP7 pour prendre en compte l'envoi de messages privés.<br/><br/>
*
* Commentaires à sebastien.jean@iut-valence.fr
*
* @author Sébastien JEAN, IUT Valence, oct. 2006
* @version 1.0
*/
public class ChatServerDispatcher extends Thread
{
/**
* Les informations (pseudo, socket) associé à chaque client enregistré.
*/
private Map<String, Socket> clients;
/**
* La liste de messages en attente de diffusion.
*/
private List<String> messages;
/**
* Constructeur sans paramètre. Initialisation d'un distributeur de
* messages.
*/
public ChatServerDispatcher()
{
super();
this.setDaemon(true);
// Initialisation des informations clients et des messages en attente
this.clients = new HashMap<String, Socket>();
this.messages = new LinkedList<String>();
}
/**
* Dépot d'un message dans la liste des messages à distribuer.
*
* @param pseudo le pseudo associé au message (le pseudo du client ou le nom
* du serveur).
* @param message le message à diffuser.
*/
public synchronized void broadCastMessage(String pseudo, String message)
{
// Ajout du message dans la liste
this.messages.add(pseudo + "> " + message);
// Notification d'ajout
this.notify();
}
/**
* Envoi d'un message privé vers un utilisateur donné.
*
* @param src_pseudo le pseudo de l'émetteur du message privé (le pseudo
* d'un client ou le nom du serveur).
* @param dest_pseudo le pseudo du récepteur du message privé.
* @param message le message à diffuser.
*/
public synchronized void unicastMessage(String src_pseudo,
String dest_pseudo, String message)
{
boolean toSend = true;
boolean sent = false;
// Recherche du socket associé au récepteur du message
// Si le récepteur est inconnu, on ignore la demande
// et on averti l'émetteur de l'échec de l'envoi
Socket destSock = this.clients.get(dest_pseudo);
if (destSock == null)
toSend = false;
// Tentative d'envoi du message
if (toSend)
{
try
{
new PrintStream(destSock.getOutputStream(), true, "UTF-8")
.println("Private message from " + src_pseudo + "> "
+ message);
sent = true;
}
catch (Exception e)
{}
}
// Recherche du socket associé à l'émetteur du message
// Si l'émetteur est inconnu (ce peut être le serveur lui-même)
// on ne fait rien de spécial. Sinon, on envoi une notification d'échec
// ou de réussite de transmission à l'émetteur.
Socket srcSock = this.clients.get(src_pseudo);
if (srcSock != null)
{
String ack = "ChatServer > Private message to " + dest_pseudo
+ " successfully sent";
if (!sent)
{
ack = "ChatServer > Private message to " + dest_pseudo
+ " could not be sent";
}
try
{
new PrintStream(srcSock.getOutputStream(), true, "UTF-8")
.println(ack);
}
catch (Exception e)
{}
}
}
/**
* Enregistrement d'un client auprès du distributeur de messages.
*
* @param pseudo le pseudonyme associé au client.
* @param sock le socket permettant la communication avec le client.
* @return <tt>true</tt> si les informations ont pu être enregistrées,
* <tt>false</tt> si un client était déjà enregistré avec le même
* pseudonyme.
*/
public synchronized boolean addClient(String pseudo, Socket sock)
{
// Vérification d'un enregistrement antérieur du client.
if (this.clients.containsKey(pseudo)) { return false; }
// Enregistrement du client le cas échéant.
return (this.clients.put(pseudo, sock) == null);
}
/**
* Désenregistrement d'un client auprès du distributeur de messages.
*
* @param pseudo le pseudonyme associé au client.
*/
public synchronized void removeClient(String pseudo)
{
this.clients.remove(pseudo);
}
/**
* Obtention du nombre de clients enregistrés.
*
* @return le nombre de clients enregistrés.
*/
public synchronized int getClientCount()
{
return this.clients.size();
}
/**
* <i>Corps</i> de la tâche.
*
* @see java.lang.Runnable#run()
*/
public void run()
{
String message = null;
while (true)
{
// En exclusion mutuelle
// Attente de la condition-événement "liste de messages non vide"
synchronized (this)
{
if (this.messages.size() == 0)
{
try
{
this.wait();
}
catch (InterruptedException e)
{
continue;
}
}
// Retrait du premier message déposé
message = this.messages.remove(0);
// Parcours de la liste des sockets pour diffuser le message
Iterator<Socket> it = this.clients.values().iterator();
while (it.hasNext())
{
// Obtention du socket suivant
Socket sock = it.next();
// Diffusion du message sur le socket
try
{
new PrintStream(sock.getOutputStream(), true, "UTF-8")
.println(message);
}
catch (Exception e)
{
// Si une erreur survient, on l'ignore
// celà peut être simplement un client qui vient de se
// déconnecter
}
}
}
}
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -