RC [entrega] [Practica 1] [Practica 2] [Practica 3] [Practica 4] [Practica 5] [info ssh] [info git]

Práctica 5 - Chat con conexiones concurrentes

Objetivos

Para esta práctica nos basaremos en los programas y protocolo que hemos creado en las prácticas anteriores. Vamos a añadir la capacidad de atender a varios clientes simultáneamente hasta un número máximo de conexiones.

Metodología

Está permitido comentar y debatir la práctica con otros grupos, incluso se recomienda probar el protocolo con otros grupos, pero bajo ningún concepto está permitido compartir o copiar código de otros grupos. Incumplir esta norma acarreará el suspenso de la práctica.

Para implementar conexiones concurrentes se recomienda emplear select o su formato más conveniente poll. no

Consideraciones previas

Cada una de las conexiones que se realicen entre cliente y servidor seguirán el protocolo descrito en la práctica 3 y el protocolo para subir y bajar ficheros descrito en la práctica 4.

Nuevas peticiones del protocolo

Vamos a añadir nuevas peticiones al protocolo: conocer los usuarios conectados, conocer los ficheros, recoger información del servicio y enviar mensajes entre usuarios y subir y bajar ficheros.

Conocer los usuarios conectados

Cuando el cliente quiera conocer qué usuarios se encuentran conectados en ese momento al servidor, intercambiarán los siguientes mensajes.

Cliente dirección Servidor
LISTA ->  
  <- LISTADO
  <- U usuario1
  <- Y tunombre
  <- U usuario2
  <-
  <- E

Dónde:

Conocer los ficheros disponibles

Cuando el cliente quiera conocer qué ficheros hay disponibles en el servidor, intercambiarán los siguientes mensajes.

Cliente dirección Servidor
FICHEROS ->  
  <- LISTADO
  <- fichero1 size1
  <- fichero2 size2
  <- fichero3 size3
  <-
  <- E

Dónde:

Recoger información del servicio

El cliente puede preguntar al servidor información sobre el tiempo que lleva conectado y el tiempo de vida del servidor.

Para ello se intercambiarán estos mensajes:

Cliente dirección Servidor
UPTIME ->  
  <- UPTIME t1 t2

Dónde:

t1 y t2 pueden ser enteros o flotantes pero deben de ser en segundos.

Enviar un mensaje al chat

Cuando el cliente quiera enviar un mensje al chat intercambiara los siguientes mensajes con el servidor

Cliente dirección Servidor
MSG el_mensaje_que_puede_contener_espacios ->  
  <- MSG nombre el_mensaje_que_puede_contener_espacios

Dónde:

El servidor enviara el mensaje de respuesta a ese cliente y a todos los demas clientes que esten conectados y correctamente autenticados. En la respuesta el servidor incluira el nombre del usuario que envia el mensaje para que los demas vean de quien viene

Eso significa que en cualquier momento cuando el cliente esta esperando otros mensajes puede llegarle un mensaje de tipo MSG. En ese caso el cliente debera procesar el MSG y seguir esperando la respuesta que esperaba.

La forma más simple para que el cliente reciba los mensajes es que envíe periódicamente peticiones de UPTIME para forzar a que se impriman los mensajes pendientes.

Objetivo 1: implementar cliente y servidor concurrente con nuevos mensajes

Implementar un servidor que acepta clientes simultáneos y soporte los dos nuevos mensajes: conocer los usuarios conectados y recoger información del tiempo.

Implementar un cliente que soporte los nuevos mensajes. El cliente es practicamente el mismo. A partir del desarrollo de la práctica anterior, en el mismo menú en el que hemos dado al usuario la opción de cambiar y conocer su nombre, vamos a añadir qué usuarios hay conectados y el tiempo que lleva el servidor funcionando y nosotros conectados. Recuerda que el proceso de registro y autentificación es automático (el usuario no interacciona con la aplicación), mientras que para estas opciones, sí que mostraremos opciones para que elija.

Si bien la forma de llamar al cliente no cambia, la del servidor sí ligeramente:

FORMATO

	servidor <puerto> <número_máximo_de_conexiones>  <userfile> <directoriodeficheros> <numero_retos_login> 


DESCRIPCIÓN

	<puerto> puerto en el que escuchar, por ejemplo 6000

	<número_máximo_de_conexiones> número máximo de clientes que podrán conectarse al servidor

	<userfile> nombre de fichero con los usuarios con el mismo formato que en la practica 3, si no se incluye se utilizara server_users

	<directoriodeficheros> nombre de un directorio en el que se subiran los ficheros que envien los usuarios

	<numero_retos_login> número máximo de retos a pedir en el login si no se incluye utilizará 3 retos

Si se alcanza ese número máximo de conexiones, el servidor denegará la conexión y la cerrará directamente.

El servidor mostrará por pantalla información relevante del proceso, aunque el objetivo es que cumpla con el protocolo. Seguidamente se muestra un ejemplo de cómo podría ser la ejecución del servidor:

$ ./servidor1 6000 2 users files 10
Escuchando conexiones en el puerto 6000
Conexión establecida desde la IP 10.1.1.123 puerto 32125
Usuario abc123 autentificado
1 usuario conectado
Usuario ddd222 autentificado
2 usuarios conectados
Nueva conexión denegada, número máximo de clientes alcanzado
Usuario abc123 ha cerrado la conexión
1 usuario conectado
Enviando información de usuarios a ddd222
Enviando información de tiempo a ddd222
Usuario ddd222 ha cerrado la conexión
No hay usuarios conectados

Objetivo 2: cliente

Realizar un cliente que cumpla el protocolo.

Esta es la especificación del cliente:

FORMATO
	cliente <ip> <puerto> <userid> [<secreto>]

DESCRIPCIÓN
	<ip> IP en formato IPv4, por ejemplo, 10.1.1.101
	<puerto> puerto al que conectarse, por ejemplo 6000
	<userid> userid para emplear en la autenticación
	<secreto> secreto para la autenticación
	El userid debe proporcionarse en la llamada a cliente y puede proporcionarse tambien el secreto. Si se proporcionan los dos el cliente utilizara ese <userid> y <secreto> para autentificarse.
	Si el secreto no se proporciona se le preguntara al usuario.
	Bajo ningun concepto el cliente cargará el secreto de un fichero y especialmente es un error que el cliente abra y cargue datos del fichero usuarios del servidor.

	El cliente se autenticará con el usuario indicado y permitirá realizar las funciones del chat: enviar y recibir mensajes a los demas y subir y bajar ficheros

Seguidamente se muestra un ejemplo de ejecución. El interfaz no es importante, puedes elegir la forma que prefieras, pero debe funcionar con el protocolo dado.

$ ./cliente 10.1.1.101 6000 mikel rcPASS4M1k3l
Autenticando con usario mikel
reto 1 respondido
reto 2 respondido
reto 3 respondido 
Autenticado OK
1- consultar nombre
2- cambiar nombre
3- ver usuarios
4- ver ficheros
5- subir fichero
6- bajar fichero
7- enviar mensaje
8- ver tiempo y mensajes recibidos
9- cerrar conexion

El cliente debe soportar al menos un interfaz minimo como ese. Pero se valorara mejorar el interfaz. Un interfaz mejor será que no haya que enviar una peticion UPTIME para ver los mensajes sino que aparezcan en cuanto lleguen. Por ejemplo algo asi

$ ./cliente 10.1.1.101 6000 mikel rcPASS4M1k3l
Autenticando con usario mikel
reto 1 respondido
reto 2 respondido
reto 3 respondido 
Autenticado OK
Lo que escriba se enviara como mensaje al chat.
Si quiere ver los usuarios escriba \users 
Si quiere ver los ficheros escriba \files
Si quiere cambiar el nombre escriba \name
Si quiere subir un fichero escriba \put fichero
Si quiere bajar un fichero escriba \get fichero
\users
Usuarios conectados: alice, bob, *mikel
Hola
mikel: Hola
alice: hola gentes
\put poster.png
He subido el poster
mikel: He subido el poster
bob: dejame ver
bob: yo he subido un nueva lista de tareas
\files
En el servidor hay estos ficheros
- poster.png
- tareas.txt
\get tareas.txt
Bajando tareas.txt

Cómo entregar el programa

En el mismo directorio para prácticas que creamos en la práctica anterior, se creará un directorio que se llame practica5. En practica5 existirán al menos estos ficheros:

El fichero Makefile tendrá al menos cuatro objetivos: all, cliente, servidor y clean:

Los ficheros que se entregan se recogerán directamente de Bitbucket y no se aceptarán otros métodos.