Servidor de correo:
Socket Servidor de mensajería:
root@psp-chat:~# python3 servidor.py
[INICIO] Servidor escuchando en 0.0.0.0:3333
import socket
import threading
# Configuraci n del servidor
HOST = '0.0.0.0' # Escucha en todas las interfaces de red
PORT = 3333 # Puerto de escucha
clients = [] # Lista para almacenar los clientes conectados
# Funci n para retransmitir mensajes a todos los clientes
def broadcast(message, client_socket):
for client in clients:
if client != client_socket: # Evitar enviar el mensaje al remitente
try:
client.send(message)
except:
# Si falla el env o, eliminar el cliente
clients.remove(client)
# Función para manejar la comunicación con un cliente
def handle_client(client_socket, client_address):
print(f"[NUEVO CLIENTE] {client_address} conectado.")
while True:
try:
# Recibir mensaje del cliente
message = client_socket.recv(1024)
if not message:
break # Si no hay mensaje, el cliente cerr la conexi n
print(f"[{client_address}] {message.decode('utf-8')}")
# Retransmitir el mensaje a los dem s clientes
broadcast(message, client_socket)
except:
print(f"[DESCONECTADO] {client_address} se ha desconectado.")
clients.remove(client_socket)
client_socket.close()
break
# Funci n principal para iniciar el servidor
def start_server():
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # IPv4, TCP
server.bind((HOST, PORT))
server.listen(5) # M ximo 5 conexiones en cola
print(f"[INICIO] Servidor escuchando en {HOST}:{PORT}")
while True:
client_socket, client_address = server.accept() # Aceptar nueva conexión
clients.append(client_socket)
print(f"[CONECTADO] Nueva conexi n desde {client_address}")
# Iniciar un hilo para manejar el cliente
client_thread = threading.Thread(target=handle_client, args=(client_socket, client_address))
client_thread.start()
# Iniciar el servidor
if __name__ == "__main__":
start_server()
import tkinter as tk
from tkinter import Menu # Importar el widget Menu
from tkinter import ttk # Importar el widget ttk
import threading
import time
import datetime
def update_time(status_bar):
"""Función que actualiza la hora y el día de la semana en un label"""
while True:
# Obtener la fecha y hora actual
now = datetime.datetime.now()
day_of_week = now.strftime("%A") # Día de la semana
time_str = now.strftime("%H:%M:%S") # Hora en formato HH:MM:SS
date_str = now.strftime("%Y-%m-%d") # Fecha en formato YYYY-MM-DD
label_text = f"{day_of_week}, {date_str} - {time_str}"
# Actualizar el label (debemos usar `after` para asegurarnos que se actualice en el hilo principal de Tkinter)
label_fecha_hora.after(1000, status_bar.config, {"text": label_text})
# Espera 1 segundo antes de actualizar de nuevo
time.sleep(1)
# Crear la ventana principal
root = tk.Tk()
root.title("Ventana Responsive")
root.geometry("1000x700") # Tamaño inicial
# Configurar la ventana principal para que sea responsive
root.columnconfigure(0, weight=0) # Columna izquierda, tamaño fijo
root.columnconfigure(1, weight=1) # Columna central, tamaño variable
root.columnconfigure(2, weight=0) # Columna derecha, tamaño fijo
root.rowconfigure(0, weight=1) # Fila principal, tamaño variable
root.rowconfigure(1, weight=0) # Barra de estado, tamaño fijo
# Crear el menú superior
menu_bar = Menu(root)
file_menu = Menu(menu_bar, tearoff=0)
file_menu.add_command(label="Nuevo")
file_menu.add_command(label="Abrir")
file_menu.add_separator()
file_menu.add_command(label="Salir", command=root.quit)
edit_menu = Menu(menu_bar, tearoff=0)
edit_menu.add_command(label="Copiar")
edit_menu.add_command(label="Pegar")
help_menu = Menu(menu_bar, tearoff=0)
help_menu.add_command(label="Acerca de")
menu_bar.add_cascade(label="Archivo", menu=file_menu)
menu_bar.add_cascade(label="Editar", menu=edit_menu)
menu_bar.add_cascade(label="Ayuda", menu=help_menu)
root.config(menu=menu_bar)
# Crear los frames laterales y el central
frame_izquierdo = tk.Frame(root, bg="lightblue", width=200)
frame_central = tk.Frame(root, bg="white")
frame_derecho = tk.Frame(root, bg="lightgreen", width=200)
# Colocar los frames laterales y el central
frame_izquierdo.grid(row=0, column=0, sticky="ns")
frame_central.grid(row=0, column=1, sticky="nsew")
frame_derecho.grid(row=0, column=2, sticky="ns")
# Configurar los tamaños fijos de los frames laterales
frame_izquierdo.grid_propagate(False)
frame_derecho.grid_propagate(False)
# Dividir el frame central en dos partes (superior variable e inferior fija)
frame_central.rowconfigure(0, weight=1) # Parte superior, tamaño variable
frame_central.rowconfigure(1, weight=0) # Parte inferior, tamaño fijo
frame_central.columnconfigure(0, weight=1) # Ocupa toda la anchura
# Crear subframes dentro del frame central
frame_superior = tk.Frame(frame_central, bg="lightyellow")
frame_inferior = tk.Frame(frame_central, bg="lightgray", height=100)
# Colocar los subframes dentro del frame central
frame_superior.grid(row=0, column=0, sticky="nsew")
frame_inferior.grid(row=1, column=0, sticky="ew")
# Fijar el tamaño de la parte inferior
frame_inferior.grid_propagate(False)
# Crear la barra de estado
barra_estado = tk.Label(root, text="Barra de estado", bg="lightgray", anchor="w")
barra_estado.grid(row=1, column=0, columnspan=3, sticky="ew")
# Notebook para las pestañas
style = ttk.Style()
style.configure("CustomNotebook.TNotebook.Tab", font=("Arial", 12, "bold"))
notebook = ttk.Notebook(frame_superior, style="CustomNotebook.TNotebook")
notebook.pack(fill="both", expand=True)
# Crear cinco solapas
for i in range(1, 6):
tab = ttk.Frame(notebook)
notebook.add(tab, text=f"Solapa {i}", padding=4)
# Añadir un Label en cada solapa para diferenciarla
label = ttk.Label(tab, text=f"Contenido de la Solapa {i}")
label.pack(pady=10)
# Barra de estado
# Dividir la barra de estado en 4 labels
# Usar pack para alinear los labels horizontalmente
label_1 = tk.Label(barra_estado, text="Estado 1", bg="green", anchor="w", width=20)
label_2 = tk.Label(barra_estado, text="Estado 2", bg="blue", anchor="w", width=20)
label_3 = tk.Label(barra_estado, text="Estado 3", bg="cyan", anchor="w", width=20)
label_4 = tk.Label(barra_estado, text="Estado 4", bg="pink", anchor="w", width=20)
label_fecha_hora = tk.Label(barra_estado, text="Hilo fecha-hora", font=("Helvetica", 14), bd=1, fg="blue", relief="sunken", anchor="w", width=20, padx=10)
label_1.pack(side="left", fill="x", expand=True)
label_2.pack(side="left", fill="x", expand=True)
label_3.pack(side="left", fill="x", expand=True)
label_4.pack(side="left", fill="x", expand=True)
label_fecha_hora.pack(side="right", fill="x", expand=True)
# barra_estado.grid(row=1, column=0, columnspan=3, sticky="ew")
update_thread = threading.Thread(target=update_time, args=(label_fecha_hora,))
update_thread.daemon = True # Hacemos el hilo un demonio para que termine con la app
update_thread.start()
# Ejecución de la aplicación
root.mainloop()
psutil.net_io_counters()
Nota:
En aplicaciones con Tkinter, el hilo principal (el que ejecuta el bucle principal mainloop
) está dedicado exclusivamente a manejar la interfaz gráfica de usuario (GUI). Si intentas ejecutar tareas largas o bloqueantes en este hilo, la interfaz se congela, lo que afecta negativamente la experiencia del usuario.
Para resolver esto, puedes usar hilos (threads) para ejecutar tareas en paralelo sin bloquear el hilo principal. Sin embargo, hay ciertos cuidados importantes al usar hilos con Tkinter:
after()
del widget raíz para programar actualizaciones en el hilo principal.queue.Queue
) para comunicar datos del hilo secundario al principal de forma segura.threading.Lock
) si es necesario.En este ejemplo, un hilo secundario ejecuta una tarea pesada y notifica a la GUI sobre el progreso sin bloquear la ventana principal:
import tkinter as tk
from tkinter import ttk
import threading
import time
from queue import Queue
class App:
def __init__(self, root):
self.root = root
self.root.title("Hilos con Tkinter")
# Etiqueta de progreso
self.progress_label = tk.Label(root, text="Progreso: 0%")
self.progress_label.pack(pady=10)
# Botón para iniciar la tarea
self.start_button = ttk.Button(root, text="Iniciar Tarea", command=self.start_task)
self.start_button.pack(pady=10)
# Cola para comunicación entre hilos
self.queue = Queue()
def start_task(self):
# Deshabilita el botón mientras se ejecuta la tarea
self.start_button.config(state="disabled")
# Crea y lanza un hilo para la tarea
thread = threading.Thread(target=self.long_task, args=(self.queue,))
thread.start()
# Inicia el monitoreo de la cola
self.monitor_queue()
def long_task(self, queue):
# Simula una tarea larga con actualizaciones de progreso
for i in range(1, 101):
time.sleep(0.05) # Simula trabajo
queue.put(i) # Envía progreso a través de la cola
def monitor_queue(self):
try:
# Obtén el progreso desde la cola
progress = self.queue.get_nowait()
self.progress_label.config(text=f"Progreso: {progress}%")
if progress == 100:
self.start_button.config(state="normal") # Rehabilita el botón al terminar
except:
pass
# Programa otra comprobación de la cola después de 100 ms
if not self.queue.empty():
self.root.after(100, self.monitor_queue)
Hilo secundario (long_task
):
time.sleep
).Cola de mensajes (queue.Queue
):
after()
para actualizaciones seguras:
after
de Tkinter se usa para programar actualizaciones periódicas en el hilo principal, evitando el acceso directo desde el hilo secundario.Deshabilitación del botón:
ttk.Progressbar
) para representar visualmente el progreso.Con este enfoque, puedes realizar tareas largas en segundo plano sin afectar la experiencia del usuario en la ventana de Tkinter.