NanoChat
Aplicación Java cuya funcionalidad es la conexión de clientes a un servidor de chat, haciendo uso de un intermediario que es un directorio o servidor con las listas de chats que gestionará las peticiones de los clientes. La aplicación gestiona los protocolos UDP y TCP para las comunicaciones entre clientes, servidores y el directorio. Proyecto final de la asignatura de Redes de Comunicaciones del segundo año del grado de Ingeniería Informática en la Universidad de Murcia.
Funcionamiento de la aplicación
Las diferentes comunicaciones se llevan a cabo a través de algunas funciones, algunas de las más importantes son:
Función | Acción |
---|---|
getServerForProtocol() | Es usada por los clientes, le envían un mensaje de petición de información sobre cierto servidor de chat al Directory, y este último deberá de buscar en su lista de servidores de chat el que el cliente ha pedido(usando el protocol que se pasa como argumento), en el caso de que ese servidor exista pues le mandarán la información necesaria(sendServerInfo), y este obtendrá su IP mediante la función getAddressFromResponse(). |
registerServerForProtocol() | Es usada por los servidores de chat y como su nombre indica, dado un protocolo intentarán registrar el servidor de chat en el server Directory, que se registrará satisfactoriamente(sendOK) a no ser que este ya esté registrado. |
processRequestFromClient() | Es la función que usa el Directory para ir analizando y tratando los distintos tipos de mensaje y peticiones que le envían tanto clientes como servidores de chat. |
A continuación se hace un breve resumen de cómo funcionan el directorio, el servidor de chat y el cliente de chat con sus respectivos autómatas de funcionamiento.
Funcionamiento del servidor de directorio
El servidor del directorio se inicializa y queda esperando a la llegada de una solicitud de un servidor o de un cliente. Este estado inicial recibe el nombre de qWAIT, y además es el único estado final del autómata. Una vez que se encuentra en este estado, puede pasar a dos estados diferentes: cuando se recibe una petición de un cliente de chat de obtener información de un servidor (rcv(getServer), se pasa al estado q3. Entonces se revisa el conjunto de los servidores almacenados, y se vuelve al estado qWAIT con la información(send(info)) o con un mensaje en el que se especifica que el servidor no se encuentra registrado en el directorio (send(empty)).
Por otro lado, cuando en el estado qWAIT se recibe una solicitud de un servidor de chat para ser registrado (rcv(registerServer)) se pasa al estado q2. En este estado se intenta registrar el servidor. Si ya existe, se retorna al estado qWAIT con la denegación del registro (send(denied)). Sin embargo, cuando esto no sucede el servidor se registra y se devuelve la confirmación de esto (send(confirmed)).
Autómata del directorio
Funcionamiento del cliente de chat
El cliente de chat tiene un estado inicial q1. Este estado además es final. Cuando el cliente decide enviar una solicitud al directorio para obtener la dirección de un servidor (send(query)), el autómata pasa al estado q2. En este estado pueden suceder diferentes cosas: si obtenemos una respuesta del directorio, volveríamos al estado inicial con la información del servidor (rcv(info)) o, en caso de no estar registrado en el directorio, con un mensaje que indica que el servidor de chat no está registrado (rcv(empty)).
Sin embargo, si se excede un tiempo máximo preestablecido (el timeout), el autómata pasa a un siguiente estado q3 idéntico en el que se vuelve a solicitar al directorio la información. El autómata está simplificado, pero este proceso se repetiría 10 veces en caso de error, y si el décimo también excede el timeout, el autómata llega al estado qerr, estado “trampa” al que se llega tras exceder todos los timeouts del que no se puede salir y es final.
Autómata del cliente
Funcionamiento del servidor de chat
El servidor de chat tiene un estado inicial q1 que además también es su único estado final. En este estado inicial se pueden mandar solicitudes al directorio para ser registrados en él (snd(registration)), pasando de esta manera al esta q2 del autómata. En este estado del autómata se puede retornar al estado inicial con la confirmación del registro (rcv(confirmed)) o, en caso de hallarse ya en el directorio, el mensaje de denegación del registro (rcv(denied)).
Sin embargo, si se excede el timeout preestablecido, se pasará a un estado q3 en el que se volverá a enviar la solicitud de registro al directorio retornando de esta manera a q2.
Autómata del servidor
Formato de los mensajes
Se han utilizado diversos formatos de mensajes durante la elaboración del nano-chat. Estos formatos se han elaborado para funcionar sobre los dos protocolos de nivel de transporte que había que utilizar: UDP para los mensajes encargados de comunicar el directorio con los clientes y servidores del chat, y TCP para el mecanismo de comunicación entre el cliente y el servidor de chat.
Mensajes de UDP
A continuación se presentan y explican brevemente los mensajes creados para la comunicación entre el directorio en la clase DirectoryThread y el cliente o servidor de chat con la clase DirectoryConnector.
- Mensaje de consulta del cliente: Tiene el código de operación opcode = 0. Es el mensaje usado por el cliente de chat para consultar al directorio la dirección de un servidor asociada a cierto protocolo (getServerForProtocol). Ocupa 5 bytes, 1 para el opcode y 4 para el protocolo (que es un entero).
- Mensaje de registro del servidor: Tiene el código de operación opcode = 1. Es el mensaje usado por el servidor de chat para solicitar su registro en el HashMap que almacena en el directorio los diferentes servidores asociados a los protocolos (registerServerForProtocol). Ocupa 9 bytes, uno para el opcode, 4 para el protocolo y 4 para el puerto del servidor.
- Mensaje de confirmación/denegación del servidor: Tiene el código de operación 2. Este mensaje es la respuesta del directorio a la solicitud de registro del servidor (sendOK), y ocupa 2 bytes, uno para el opcode y otro para un byte b que está programado para poder tener dos estados posibles. El valor b puede tomar el valor 1 en el que se confirma la solicitud cuando el protocolo del servidor no tiene asociado ningún servidor en el directorio y de esta manera se confirma el registro; o puede tomar el valor 0 cuando ya existe un servidor asociado al protocolo denegando de esta manera el registro.
- Mensaje de información del servidor: Tiene el opcode = 3. Es el mensaje que responde el directorio a una solicitud del cliente getServerForProtocol() cuando existe el servidor en el directorio (sendServerInfo). Ocupa 9 bytes, 1 para el opcode, 4 para la dirección IP en formato de array de bytes y 4 para el puerto del servidor (entero).
- Mensaje de no existencia del servidor: Tiene el código de operación 4. Este mensaje complementa al anterior, ya que es el mensaje que se manda cuando para la solicitud mencionada del cliente no hay servidor registrado (sendEmpty). Consta de un solo byte, el del opcode.
Mensajes una vez conectado al servidor de chat
A continuación se presentan los diferentes formatos de mensajes utilizados para la comunicación entre cliente y servidor, referente a las tareas del boletín 6. Se ha utilizado lenguaje de marcas. Posteriormente se encuentran los mensajes de respuesta.
Mensajes del cliente
Mensaje | Opcode | Comando | Tipo de mensaje |
---|---|---|---|
Registrarte en el servidor con un nick | 3 | “nick nombre”(COM_NICK) | NCRoomMessage |
Intentar entrar a una sala | 2 | “enter nombre”(COM_ENTER) | NCRoomMessage |
Pedir una lista de las salas existentes en el servidor | 1 | “roomlist”(COM_ROOMLIST) | NCRoomMessage |
Enviar un mensaje de chat al servidor | 4 | “send mensaje”(COM_SEND) | NCRoomMessage |
Salir de una sala del servidor de chat | 5 | “exit”(COM_EXIT) | NCOpcodeMessage |
Pedir información acerca de la sala en la que te encuentras | 7 | “roominfo”(COM_ROOMINFO) | NCOpcodeMessage |
Salir del servidor de chat | 8 | “quit”(COM_QUIT) | |
Pedir ayuda acerca de los comandos disponibles | 9 | “help”(COM_HELP) | NCPmMessage |
Enviar un mensaje privado a un usuario de tu sala | 10 | “sendpm user mensaje”(COM_SENDPM) | NCRoomMessage |
Cambiar el nombre de la sala | 11 | ”changeroomname nombre”(COM_CHANGEROOMNAME) | NCRoomMessage |
Esperar una supuesta recepción de mensaje en la sala | 12 | " "(COM_SOCKET_IN) |
Mensajes de respuesta
Mensaje | Opcode | Código de opcode | Tipo de mensaje |
---|---|---|---|
El nick ha sido aceptado | 2 | OP_NICK_OK | NCOpcodeMessage |
El nick ha sido rechazado | 2 | OP_NICK_DUPLICATED | NCOpcodeMessage |
El cliente ha sido aceptado en la sala | 21 | OP_ACCEPTED | NCOpcodeMessage |
El cliente no ha sido aceptado en la sala | 22 | OP_DENIED | NCOpcodeMessage |
El cliente “x” ha salido de la sala | 25 | OP_USERLEFT | NCRoomMessage |
El cliente “x” ha entrado en la sala | 26 | OP_USERENTERED | NCRoomMessage |
Se ha cambiado el nombre de la sala | 27 | OP_NAMECHANGED | NCRoomMessage |
La lista de mensajes que tiene guardados la sala | 28 | OP_NAMENOTCHANGED | NCRoomMessage |
La lista de la información de las salas | 51 | OP_INFOLISTED | NCListMessage |
El mensaje que envía un usuario por la sala | 61 | OP_RCVMESSAGE | NCRoomMessage |
El mensaje privado ha sido enviado satisfactoriamente | 63 | OP_SENT | NCRoomMessage |
El mensaje privado no se ha podido enviar | 64 | OP_NOTSENT | NCRoomMessage |
La lista de mensajes que tiene guardados la sala | 66 | OP_HISTORYPRINTED | NCStringListMessage |