Skip to content

Latest commit

History

12 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

TCP Chat

Servidor TCP (Server.java):

publicclassServerimplementsRunnable {
privateArrayList<ConnectionHandler> connections;
privateFilef = newFile("messages.txt");
privateServerSocketserver;
privatebooleandone;
privateExecutorServicepool;
privateList<String> users = newArrayList<>();
publicServer() {
connections = newArrayList<>();
done = false;
}
  • Atributos:

    • connections: Lista de manejadores de conexiones activas.
    • f: Archivo donde se guardan los mensajes.
    • server: Socket del servidor.
    • done: Flag para controlar si el servidor está en funcionamiento.
    • pool: Pool de hilos para manejar múltiples conexiones.
    • users: Lista de nicknames de los usuarios conectados.
  • Constructor: Inicializa la lista de conexiones y el flag done.

    Método run

    @Overridepublicvoidrun() {
    try {
    server = newServerSocket(9999);
    pool = Executors.newCachedThreadPool();
    while (!done) {
    Socketclient = server.accept();
    ConnectionHandlerhandler = newConnectionHandler(client);
    connections.add(handler);
    pool.execute(handler);
    }
    } catch (Exceptione) {
    shutdown();
    }
    }
  • run(): Inicia el servidor en el puerto 9999, crea un pool de hilos y acepta conexiones de clientes en un bucle. Cada conexión se maneja en un nuevo hilo usando ConnectionHandler.

Método broadcast

publicvoidbroadcast(Stringmessage) {
for (ConnectionHandlerch : connections) {
if (ch != null) {
ch.sendMessage(message);
}
}
saveMessage(message);
}
  • broadcast(String message): Envía un mensaje a todos los clientes conectados y lo guarda en un archivo.

Método saveMessage

privatevoidsaveMessage(Stringmessage) {
try {
BufferedWriterbw = newBufferedWriter(newFileWriter(f, true));
bw.write(message);
bw.newLine();
bw.close();
} catch (IOExceptione) {
//ignore
}
}
  • saveMessage(String message): Guarda el mensaje en el archivo messages.txt.

Método shutdown

publicvoidshutdown() {
try {
done = true;
pool.shutdown();
if (!server.isClosed()) {
server.close();
}
for (ConnectionHandlerch : connections) {
ch.shutdown();
}
} catch (IOExceptione) {
// ignore
}
}
  • shutdown(): Apaga el servidor, cierra el socket del servidor y todas las conexiones activas.

Clase ConnectionHandler

classConnectionHandlerimplementsRunnable {
privateSocketclient;
privateBufferedReaderin;
privatePrintWriterout;
privateStringnickname;
publicConnectionHandler(Socketclient) {
this.client = client;
}
  • Atributos:

    • client: Socket del cliente.
    • in: Lector de entradas del cliente.
    • out: Escritor de salidas hacia el cliente.
    • nickname: Nickname del usuario.
  • Constructor: Inicializa el socket del cliente.

Método run en ConnectionHandler

@Overridepublicvoidrun() {
try {
out = newPrintWriter(client.getOutputStream(), true);
in = newBufferedReader(newInputStreamReader(client.getInputStream()));
out.println("Hello!...");
out.println("Please enter a nickname : ");
validateUser(out, in);
Stringmessage;
while ((message = in.readLine()) != null) {
if (message.startsWith("/nick ")) {
String[] messageSplit = message.split(" ", 2);
if (messageSplit.length == 2) {
validateRename(messageSplit[1], out);
} else {
out.println("No nickname provided!");
}
} elseif (message.startsWith("/quit")) {
broadcast(nickname + " left the chat!");
System.out.println(nickname + " left the chat");
shutdown();
} else {
broadcast(nickname + ": " + message);
}
}
} catch (SocketExceptione) {
System.out.println("There was an Exception with a client");
} catch (IOExceptione) {
shutdown();
}
}
  • run(): Maneja la interacción con el cliente. Solicita y valida el nickname del usuario. Procesa los comandos /nick para cambiar el nickname y /quit para desconectarse. Reenvía los mensajes al resto de usuarios.

Métodos Auxiliares en ConnectionHandler

  • validateRename: Valida y cambia el nickname del usuario.
privatevoidvalidateRename(Strings, PrintWriterout) {
if (users.contains(s)) {
out.println("User not available, it's already in use");
} else {
broadcast(nickname + " renamed themselves to " + s);
System.out.println(nickname + " renamed themselves to " + s);
nickname = s;
out.println("Successfully changed nickname to " + nickname);
}
}
  • validateUser: Valida el nickname del usuario al conectarse. Si el usuario solicita ver mensajes anteriores, los muestra.
privatevoidvalidateUser(PrintWriterout, BufferedReaderin) {
try {
do {
nickname = in.readLine();
StringwatchMessages[] = nickname.split(" ");
if (watchMessages.length > 1) {
nickname = watchMessages[0];
Stringmessages = watchMessages[1];
if (messages.equalsIgnoreCase("Y")) {
showPrevoiusMesssages(out);
}
}
if (users.contains(nickname)) {
out.println(nickname + " is not an available username as it is already in use!");
}
} while (users.contains(nickname));
users.add(nickname);
System.out.println(nickname + " connected");
broadcast(nickname + " joined the chat!");
} catch (SocketExceptione) {
System.out.println("No nickname provided");
} catch (IOExceptione) {
thrownewRuntimeException(e);
}
}
  • showPrevoiusMesssages: Muestra los mensajes anteriores al usuario si así lo solicita.
privatevoidshowPrevoiusMesssages(PrintWriterout) {
try {
out.println("------------------ These are the previous messages ------------------");
BufferedReaderbr = newBufferedReader(newFileReader(f));
Stringline;
try {
while ((line = br.readLine()) != null) {
out.println(line);
}
} catch (EOFExceptione) {
br.close();
}
} catch (IOExceptione) {
thrownewRuntimeException(e);
}
}
  • sendMessage: Envía un mensaje al cliente.
publicvoidsendMessage(Stringmessage) {
out.println(message);
}
  • shutdown: Cierra la conexión del cliente y elimina su nickname de la lista de usuarios.
publicvoidshutdown() {
try {
in.close();
out.close();
users.remove(nickname);
if (!client.isClosed()) {
client.close();
}
} catch (IOExceptione) {
// ignore
}
}
}
  • main: Inicia el servidor ejecutando el método run.
publicstaticvoidmain(String[] args) {
Serverserver = newServer();
server.run();
}

Resumen

Este código implementa un servidor de chat multiusuario en Java utilizando sockets TCP. El servidor:

  1. Acepta conexiones de múltiples clientes.
  2. Valida los nicknames para asegurar que sean únicos.
  3. Permite a los usuarios cambiar su nickname y desconectarse con comandos específicos.
  4. Difunde los mensajes a todos los clientes conectados.
  5. Guarda los mensajes en un archivo para que los nuevos usuarios puedan ver el historial si así lo desean.

Este servidor maneja las conexiones concurrentemente utilizando un pool de hilos, lo que le permite escalar a múltiples usuarios simultáneamente. Claro, a continuación se explica el código del cliente en Java para un chat TCP.

Cliente TCP (Client.java):

publicclassClientimplementsRunnable {
privateSocketclient;
privateBufferedReaderin;
privatePrintWriterout;
privatebooleandone;
  • Atributos:
    • client: El socket que se conecta al servidor.
    • in: Un BufferedReader para leer mensajes del servidor.
    • out: Un PrintWriter para enviar mensajes al servidor.
    • done: Un flag booleano para indicar cuándo cerrar la conexión.

Método run

@Overridepublicvoidrun() {
try {
client = newSocket("127.0.0.1", 9999);
out = newPrintWriter(client.getOutputStream(), true);
in = newBufferedReader(newInputStreamReader(client.getInputStream()));
InputHandlerinHandler = newInputHandler();
Threadt = newThread(inHandler);
t.start();
StringinMessage;
while((inMessage = in.readLine()) != null){
System.out.println(inMessage);
}
} catch (Exceptione){
shutdown();
}
}
  • run():
    1. Conexión al Servidor: Crea un socket que se conecta al servidor en la dirección 127.0.0.1 y el puerto 9999.
    2. Inicialización de out e in: Configura los flujos de entrada y salida para comunicarse con el servidor.
    3. Manejo de Entradas del Usuario: Crea y arranca un nuevo hilo InputHandler para gestionar las entradas del usuario desde la consola.
    4. Recepción de Mensajes: Lee mensajes del servidor en un bucle y los imprime en la consola.
    5. Manejo de Excepciones: Si ocurre una excepción, se llama al método shutdown.

Método shutdown

publicvoidshutdown(){
out.println("/quit");
done = true;
try{
in.close();
out.close();
if (!client.isClosed()){
client.close();
}
}catch (IOExceptione){
// ignore
}
}
  • shutdown():
    1. Envía el Comando de Desconexión: Envía el mensaje /quit al servidor para indicar la desconexión.
    2. Cierra Recursos: Cierra los flujos de entrada y salida y el socket del cliente.
    3. Manejo de Excepciones: Ignora cualquier excepción de E/S que ocurra durante el cierre de recursos.

Clase InputHandler

classInputHandlerimplementsRunnable {
@Overridepublicvoidrun() {
try {
BufferedReaderinReader = newBufferedReader(newInputStreamReader(System.in));
while(!done){
Stringmessage = inReader.readLine();
if (message.equals("/quit")){
out.println(message);
inReader.close();
shutdown();
} else {
out.println(message);
}
}
} catch (IOExceptione){
shutdown();
}
}
}

La subclase InputHandler implementa Runnable y gestiona las entradas del usuario:

  1. Lectura de la Consola: Lee mensajes desde la entrada estándar (teclado).
  2. Envío de Mensajes: Envía los mensajes al servidor.
  3. Comando de Salida: Si el usuario escribe /quit, cierra los recursos y llama al método shutdown.

Método main

publicstaticvoidmain(String[] args) {
Clientclient = newClient();
client.run();
}
  • main: Crea una instancia de Client y llama a su método run para iniciar la ejecución del cliente.

Resumen

Este código implementa un cliente de chat que se conecta a un servidor en una dirección y puerto específicos. Maneja la comunicación bidireccional con el servidor, permitiendo al usuario enviar mensajes desde la consola y recibir mensajes del servidor. Además, gestiona la desconexión limpia del cliente mediante el comando /quit.

About

No description or website provided.

Topics

Resources

Stars

0 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages