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