commit
d87199c089
@ -0,0 +1,96 @@
|
|||||||
|
SERVIDOR DE ESTADO DE CLIENTES
|
||||||
|
|
||||||
|
REQUISITOS
|
||||||
|
|
||||||
|
· Servidor multiusuario
|
||||||
|
· Controla en todo momento cuantos clientes tiene conectados (hilos)
|
||||||
|
· Un cliente cuando se conecta envía su propio nombre.
|
||||||
|
· Cada 5 minutos envía un mensaje a todos los clientes indicando el número de ordenadores que tiene conectado.
|
||||||
|
· Si un cliente se desconecta, envía un mensaje a todos avisando que se ha desconectado
|
||||||
|
|
||||||
|
------------
|
||||||
|
| SERVIDOR |
|
||||||
|
------------
|
||||||
|
|
||||||
|
-- MÉTODO INICIAR SERVIDOR
|
||||||
|
|
||||||
|
Este método se encarga de iniciar el servidor. Toma como argumentos el host (dirección IP) y el puerto en el que se escucharán las conexiones entrantes de los clientes, con ello crea un socket y lo enlaza al host y puerto especificado.
|
||||||
|
|
||||||
|
Pone el socket en modo de escucha para aceptar conexiones entrantes e inicia un bucle infinito para escuchar conexiones.
|
||||||
|
Por cada conexión entrante, crea un hilo separado para manejar al cliente.
|
||||||
|
|
||||||
|
|
||||||
|
-- MANEJAR_CLIENTES
|
||||||
|
|
||||||
|
Este metodo maneja la forma de interactuar del cliente con el servidor de forma individual, recibe como argumentos el socket del cliente y el diccionario de los clientes conectados.
|
||||||
|
|
||||||
|
Espera a recibir el nombre del cliente y luego lo agrega al diccionario.
|
||||||
|
|
||||||
|
|
||||||
|
En un bucle infinito, espera 5 segundos y luego:
|
||||||
|
Actualiza la lista de usuarios y el contador de usuarios en la interfaz gráfica del servidor.
|
||||||
|
Envía al cliente un mensaje con el número de clientes conectados.
|
||||||
|
Maneja cualquier excepción que pueda ocurrir durante la comunicación con el cliente, eliminando al cliente del diccionario y cerrando su socket.
|
||||||
|
Informa a los demás clientes sobre la desconexión del cliente actual.
|
||||||
|
|
||||||
|
|
||||||
|
ACTUALIZAR LISTA USUARIOS
|
||||||
|
|
||||||
|
Este método actualiza la lista de usuarios en la interfaz gráfica del servidor.
|
||||||
|
Este método se encarga de actualizar la lista de usuarios de la interfaz gráfica asocciada al servidor, como argumentos recibe el diccionario de clientes y obtiene los nombres.
|
||||||
|
|
||||||
|
Cada vez limia la interfaz y los agrega a la vista.
|
||||||
|
|
||||||
|
ACTUALIZAR CONTADOR USUARIOS
|
||||||
|
|
||||||
|
Este método actualiza el contador de usuarios en la interfaz gráfica del servidor, recibe como argumento el contador de usuarios.
|
||||||
|
Actualiza el texto del contador con el número de usuarios conectados.
|
||||||
|
|
||||||
|
|
||||||
|
GENERAR INTERFAZ
|
||||||
|
|
||||||
|
Este métods se encarga de generar la interfaz grafica estableciendo el diseño correspondiente,
|
||||||
|
con un contador y una lista de usuarios conectados.
|
||||||
|
Espera en bucle la interaccion de los clientes.
|
||||||
|
|
||||||
|
MAIN
|
||||||
|
|
||||||
|
Simplemente es el bloque de inicializacion de la aplicacion
|
||||||
|
|
||||||
|
------------
|
||||||
|
| CLIENTE |
|
||||||
|
------------
|
||||||
|
|
||||||
|
PRINCIPAL:
|
||||||
|
|
||||||
|
Esta funcion se encarga de generar la interfaz gráfica del cliente, utilizando Tkinter,
|
||||||
|
ademas de establecer una entrada de texto para el nombre del cliente junto con dos botones para
|
||||||
|
enviar el nombre del cliente al servidor y desconectarse del mismo.
|
||||||
|
Esta función es el punto de entrada principal para la interfaz gráfica del cliente.
|
||||||
|
|
||||||
|
Establece los eventos de clic de los botones para llamar a las funciones correspondientes enviar_nombre_callback y desconectar.
|
||||||
|
|
||||||
|
ENVIAR NOMBRE
|
||||||
|
|
||||||
|
Esta función se encarga de enviar el nombre ingresado por el usuario al servidor.
|
||||||
|
Recibe como argumentos el nombre ingresado por el usuario, el campo de entrada de nombre y el botón de enviar.
|
||||||
|
|
||||||
|
Si la conexión esta en modo activa, envia el nombre al servidor utilizando el socket del cliente.
|
||||||
|
Espera recibir la respuesta del servidor para imprimirlo por consola.
|
||||||
|
|
||||||
|
Deshabilita el campo de entrada y el botón de enviar después de enviar el nombre para evitar que el cliente haga envios repetidos.
|
||||||
|
|
||||||
|
|
||||||
|
DESCONECTAR
|
||||||
|
|
||||||
|
Esta función se encarga de desconectar al cliente del servidor.
|
||||||
|
Si la conexión está activa (true), envía al servidor un mensaje para desconectarse y cierra el socket del cliente.
|
||||||
|
Después de desconectar, cambia el estado de conectado (false).
|
||||||
|
|
||||||
|
|
||||||
|
MAIN
|
||||||
|
|
||||||
|
Simplemente es el bloque de inicializacion de la aplicacion
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -0,0 +1,72 @@
|
|||||||
|
import socket
|
||||||
|
import tkinter as tk
|
||||||
|
|
||||||
|
# CREAR SOCKET TCP/IP
|
||||||
|
socket_cliente = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||||
|
socket_cliente.connect(('localhost', 8088))
|
||||||
|
|
||||||
|
#ESTADO CONEXION
|
||||||
|
conectado = True
|
||||||
|
|
||||||
|
def principal():
|
||||||
|
|
||||||
|
# VENTANA
|
||||||
|
raiz = tk.Tk()
|
||||||
|
raiz.title("Cliente")
|
||||||
|
|
||||||
|
# LABEL INGRESAR NOMBRE
|
||||||
|
entrada_nombre = tk.Entry(raiz, font=("Arial", 14))
|
||||||
|
entrada_nombre.pack(pady=10)
|
||||||
|
|
||||||
|
# ENVIAR NOMBRE AL SERVIDOR
|
||||||
|
def enviar_nombre_callback():
|
||||||
|
nombre = entrada_nombre.get()
|
||||||
|
enviar_nombre(nombre, entrada_nombre, boton_enviar)
|
||||||
|
|
||||||
|
# Botón para enviar el nombre
|
||||||
|
boton_enviar = tk.Button(raiz, text="Enviar Nombre", command=enviar_nombre_callback)
|
||||||
|
boton_enviar.pack(pady=5)
|
||||||
|
|
||||||
|
# Botón para desconectar
|
||||||
|
boton_desconectar = tk.Button(raiz, text="Desconectar", command=desconectar)
|
||||||
|
boton_desconectar.pack(pady=5)
|
||||||
|
|
||||||
|
# Iniciar el bucle de eventos de la interfaz gráfica
|
||||||
|
raiz.mainloop()
|
||||||
|
|
||||||
|
|
||||||
|
def enviar_nombre(nombre, entrada_nombre, boton_enviar):
|
||||||
|
global conectado
|
||||||
|
try:
|
||||||
|
if conectado:
|
||||||
|
# ENVIAR NOMBRE
|
||||||
|
socket_cliente.send(nombre.encode())
|
||||||
|
|
||||||
|
#RESPUESTA SERVIDOR
|
||||||
|
respuesta = socket_cliente.recv(1024).decode()
|
||||||
|
print(respuesta)
|
||||||
|
|
||||||
|
# DESHABILITAR
|
||||||
|
entrada_nombre.config(state=tk.DISABLED)
|
||||||
|
boton_enviar.config(state=tk.DISABLED)
|
||||||
|
except Exception as e:
|
||||||
|
print("Error:", e)
|
||||||
|
conectado = False
|
||||||
|
|
||||||
|
def desconectar():
|
||||||
|
global conectado
|
||||||
|
try:
|
||||||
|
if conectado:
|
||||||
|
# NOTIFICAR AL SERVIDOR
|
||||||
|
socket_cliente.send("desconectar".encode())
|
||||||
|
|
||||||
|
# CERRAR SOCKET
|
||||||
|
socket_cliente.close()
|
||||||
|
conectado = False
|
||||||
|
except Exception as e:
|
||||||
|
print("Error al desconectar:", e)
|
||||||
|
|
||||||
|
|
||||||
|
# BLOQUE DE INICIALIZACION
|
||||||
|
if __name__ == "__main__":
|
||||||
|
principal()
|
@ -0,0 +1,125 @@
|
|||||||
|
import socket
|
||||||
|
import threading
|
||||||
|
import time
|
||||||
|
import tkinter as tk
|
||||||
|
|
||||||
|
#LISTA USUARIOS
|
||||||
|
lista_usuarios = None
|
||||||
|
|
||||||
|
def iniciar_servidor(host, puerto):
|
||||||
|
global lista_usuarios
|
||||||
|
|
||||||
|
#SOCKET
|
||||||
|
socket_servidor = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||||
|
socket_servidor.bind((host, puerto))
|
||||||
|
|
||||||
|
#ESCUCHA
|
||||||
|
socket_servidor.listen(1)
|
||||||
|
print(f"SERVIDOR INICIADO EN LA DIRECCION {host}:{puerto}")
|
||||||
|
|
||||||
|
# DICCIONARIO
|
||||||
|
clientes = {}
|
||||||
|
|
||||||
|
# BUCLE INFINITO PARA ACCEPTAR CONEXIONES
|
||||||
|
while True:
|
||||||
|
# ACCEPTAR CONEXION
|
||||||
|
socket_cliente, direccion = socket_servidor.accept()
|
||||||
|
|
||||||
|
# CREAR UN NUEVO HILO POR CADA CLIENTE
|
||||||
|
hilo_cliente = threading.Thread(target=manejar_cliente, args=(socket_cliente, clientes))
|
||||||
|
hilo_cliente.start()
|
||||||
|
|
||||||
|
|
||||||
|
def manejar_cliente(socket_cliente, clientes):
|
||||||
|
|
||||||
|
# NOMBRE CLIENTE
|
||||||
|
nombre = socket_cliente.recv(1024).decode()
|
||||||
|
|
||||||
|
# AGREGAMOS CLIENTES AL DICCIONARIO CON UN NOMBRE
|
||||||
|
clientes[socket_cliente] = nombre
|
||||||
|
|
||||||
|
print(f"{nombre} conectado desde {socket_cliente.getpeername()}")
|
||||||
|
|
||||||
|
# Bucle infinito para manejar la interacción con el cliente
|
||||||
|
while True:
|
||||||
|
try:
|
||||||
|
# Espera 5 segundos
|
||||||
|
time.sleep(5)
|
||||||
|
|
||||||
|
# Obtiene el número de clientes conectados
|
||||||
|
clientes_conectados = len(clientes)
|
||||||
|
|
||||||
|
# Actualiza la lista de usuarios en la interfaz gráfica
|
||||||
|
actualizar_lista_usuarios(clientes)
|
||||||
|
|
||||||
|
# Actualiza el contador en la GUI del servidor
|
||||||
|
actualizar_contador_usuarios(clientes_conectados)
|
||||||
|
|
||||||
|
# Construye el mensaje con el número de clientes conectados
|
||||||
|
mensaje = f"CANTIDAD DE CLIENTES CONECTADOS: {clientes_conectados}"
|
||||||
|
|
||||||
|
# Envía el mensaje al cliente actual
|
||||||
|
socket_cliente.send(mensaje.encode())
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print(e)
|
||||||
|
# Maneja cualquier excepción eliminando al cliente del diccionario y cerrando su socket
|
||||||
|
if socket_cliente in clientes:
|
||||||
|
del clientes[socket_cliente]
|
||||||
|
socket_cliente.close()
|
||||||
|
# Envía un mensaje a los clientes restantes informando que este cliente se ha desconectado
|
||||||
|
for cliente in clientes:
|
||||||
|
cliente.send(f"{nombre} DESCONECTADO".encode())
|
||||||
|
break
|
||||||
|
|
||||||
|
def actualizar_lista_usuarios(clientes):
|
||||||
|
global lista_usuarios
|
||||||
|
# Obtener los nombres de usuario de los clientes conectados
|
||||||
|
usuarios_conectados = [nombre for cliente, nombre in clientes.items()]
|
||||||
|
|
||||||
|
# Limpiar la lista de usuarios en la interfaz gráfica
|
||||||
|
lista_usuarios.delete(0, tk.END)
|
||||||
|
|
||||||
|
# Agregar los usuarios conectados a la lista de usuarios en la interfaz gráfica
|
||||||
|
for usuario in usuarios_conectados:
|
||||||
|
lista_usuarios.insert(tk.END, usuario)
|
||||||
|
|
||||||
|
def actualizar_contador_usuarios(contador):
|
||||||
|
global contador_usuarios
|
||||||
|
contador_usuarios.config(text=str(contador))
|
||||||
|
|
||||||
|
|
||||||
|
def generar_interfaz():
|
||||||
|
global lista_usuarios
|
||||||
|
global contador_usuarios
|
||||||
|
|
||||||
|
# VENTANA
|
||||||
|
ventana = tk.Tk()
|
||||||
|
ventana.title("Estado del servidor")
|
||||||
|
|
||||||
|
# CONTADOR
|
||||||
|
contador_usuarios = tk.Label(ventana, text="0", font=("Arial", 72), fg="green")
|
||||||
|
contador_usuarios.pack(pady=50)
|
||||||
|
|
||||||
|
# TITULO
|
||||||
|
titulo_nombre_clientes = tk.Label(ventana, text="NOMBRE CLIENTES CONECTADOS", font=("Arial", 18))
|
||||||
|
titulo_nombre_clientes.pack()
|
||||||
|
|
||||||
|
#LISTA USUARIOS ACTIVOS
|
||||||
|
lista_usuarios = tk.Listbox(ventana)
|
||||||
|
lista_usuarios.pack()
|
||||||
|
|
||||||
|
#ESPERAR EVENTOS
|
||||||
|
ventana.mainloop()
|
||||||
|
|
||||||
|
# Bloque principal
|
||||||
|
if __name__ == "__main__":
|
||||||
|
# Definición del host y puerto del servidor
|
||||||
|
HOST = 'localhost'
|
||||||
|
PUERTO = 8088
|
||||||
|
|
||||||
|
# Inicia el servidor en un hilo de ejecución separado
|
||||||
|
threading.Thread(target=iniciar_servidor, args=(HOST, PUERTO)).start()
|
||||||
|
|
||||||
|
# Crea la interfaz gráfica en un hilo de ejecución separado
|
||||||
|
threading.Thread(target=generar_interfaz).start()
|
Loading…
Reference in new issue