From 5cf27fb016fe391a833203661fd2bdcd1ce1a8f6 Mon Sep 17 00:00:00 2001 From: Juanposo Date: Mon, 1 Dec 2025 19:28:29 -0300 Subject: [PATCH] =?UTF-8?q?Ya=20ahora=20est=C3=A1=20pulentopolis?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- jptesting.py => jp_beta.py | 0 jp_main.py | 271 +++++++++++++++++++++++++++++++++++++ 2 files changed, 271 insertions(+) rename jptesting.py => jp_beta.py (100%) create mode 100644 jp_main.py diff --git a/jptesting.py b/jp_beta.py similarity index 100% rename from jptesting.py rename to jp_beta.py diff --git a/jp_main.py b/jp_main.py new file mode 100644 index 0000000..c9b018e --- /dev/null +++ b/jp_main.py @@ -0,0 +1,271 @@ +import socket +import threading +import tkinter as tk +from tkinter import ttk, filedialog +import os +import time + + +# ============================================================ +# UTILIDADES DE RED +# ============================================================ + +def obtener_ip_local(): + s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + try: + s.connect(("8.8.8.8", 80)) + ip = s.getsockname()[0] + s.close() + return ip + except: + return "0.0.0.0" + + +def obtener_puerto_disponible(): + for puerto in range(5000, 5101): + try: + s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + s.bind(("0.0.0.0", puerto)) + s.close() + return puerto + except: + continue + raise Exception("No hay puertos disponibles entre 5000–5100") + + +MI_IP = obtener_ip_local() +MI_PUERTO = obtener_puerto_disponible() +ANUNCIO_PUERTO = 6000 # UDP broadcast para descubrir dispositivos +BUFFER = 4096 + + +# ============================================================ +# SERVIDOR TCP RECEPCIÓN ARCHIVOS +# ============================================================ + +def servidor_tcp(): + if not os.path.exists("recibidos"): + os.makedirs("recibidos") + + srv = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + srv.bind(("0.0.0.0", MI_PUERTO)) + srv.listen(5) + + while True: + try: + conn, addr = srv.accept() + info = conn.recv(1024).decode() + nombre, tam = info.split("|") + tam = int(tam) + + ruta = f"recibidos/{nombre}" + + with open(ruta, "wb") as f: + recibido = 0 + while recibido < tam: + datos = conn.recv(BUFFER) + if not datos: + break + f.write(datos) + recibido += len(datos) + + conn.send(b"OK") + conn.close() + + except Exception as e: + print("Error en servidor:", e) + + +# ============================================================ +# SERVIDOR DE ANUNCIOS UDP +# ============================================================ + +def servidor_anuncios(): + s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + s.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1) + + while True: + time.sleep(1) + anuncio = f"DEVICE|{MI_IP}|{MI_PUERTO}" + s.sendto(anuncio.encode(), ('', ANUNCIO_PUERTO)) + + +# ============================================================ +# ESCANEAR RED (recibir anuncios) +# ============================================================ + +def descubrir_dispositivos(timeout=2): + dispositivos = {} + + s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + s.bind(("0.0.0.0", ANUNCIO_PUERTO)) + s.settimeout(timeout) + + start = time.time() + + while time.time() - start < timeout: + try: + data, addr = s.recvfrom(1024) + msg = data.decode() + + if msg.startswith("DEVICE"): + _, ip, puerto = msg.split("|") + + # ignoramos nuestro propio equipo + if ip != MI_IP: + dispositivos[ip] = int(puerto) + + except: + continue + + return dispositivos + + +# ============================================================ +# CLIENTE TCP +# ============================================================ + +def enviar_archivo(ruta, ip, puerto): + tam = os.path.getsize(ruta) + nombre = os.path.basename(ruta) + + cli = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + cli.connect((ip, puerto)) + cli.send(f"{nombre}|{tam}".encode()) + + with open(ruta, "rb") as f: + while True: + datos = f.read(BUFFER) + if not datos: + break + cli.send(datos) + + resp = cli.recv(1024) + cli.close() + return resp == b"OK" + + +# ============================================================ +# INTERFAZ TKINTER +# ============================================================ + +class App(tk.Tk): + def __init__(self): + super().__init__() + + self.title("Enviador de archivos") + self.geometry("420x360") + self.resizable(False, False) + + self.frame_actual = None + self.mostrar_home() + + # -------------------------------------------------------- + + def reemplazar_pantalla(self, frame): + if self.frame_actual: + self.frame_actual.destroy() + self.frame_actual = frame + self.frame_actual.pack(fill="both", expand=True) + + # -------------------------------------------------------- + # PANTALLA HOME + # -------------------------------------------------------- + + def mostrar_home(self): + frame = tk.Frame(self) + + tk.Label(frame, text="Tu IP:", font=("Arial", 16)).pack(pady=10) + tk.Label(frame, text=MI_IP, font=("Arial", 20, "bold")).pack(pady=10) + + ttk.Button(frame, text="Buscar equipos", command=self.mostrar_dispositivos)\ + .pack(pady=20) + + self.reemplazar_pantalla(frame) + + # -------------------------------------------------------- + # LISTA DE DISPOSITIVOS + # -------------------------------------------------------- + + def mostrar_dispositivos(self): + frame = tk.Frame(self) + + tk.Label(frame, text="Buscando equipos...", font=("Arial", 16)).pack(pady=10) + self.reemplazar_pantalla(frame) + self.update() + + dispositivos = descubrir_dispositivos() + + frame = tk.Frame(self) + + tk.Label(frame, text="Equipos encontrados:", font=("Arial", 16)).pack(pady=10) + + if not dispositivos: + tk.Label(frame, text="No se encontró ningún equipo.", + font=("Arial", 14), fg="red").pack(pady=20) + ttk.Button(frame, text="Volver", command=self.mostrar_home).pack() + self.reemplazar_pantalla(frame) + return + + for ip, puerto in dispositivos.items(): + ttk.Button( + frame, + text=f"{ip}:{puerto}", + command=lambda i=ip, p=puerto: self.seleccionar_archivo(i, p) + ).pack(pady=5) + + ttk.Button(frame, text="Volver", command=self.mostrar_home).pack(pady=20) + + self.reemplazar_pantalla(frame) + + # -------------------------------------------------------- + # SELECCIONAR ARCHIVO + # -------------------------------------------------------- + + def seleccionar_archivo(self, ip, puerto): + ruta = filedialog.askopenfilename(title="Seleccionar archivo") + + if ruta: + ok = enviar_archivo(ruta, ip, puerto) + if ok: + self.mostrar_confirmacion() + else: + self.mostrar_error() + + # -------------------------------------------------------- + # PANTALLAS DE CONFIRMACIÓN + # -------------------------------------------------------- + + def mostrar_confirmacion(self): + frame = tk.Frame(self) + + tk.Label(frame, text="Archivo enviado con éxito 🎉", + font=("Arial", 16), fg="green").pack(pady=40) + + ttk.Button(frame, text="Volver al inicio", command=self.mostrar_home)\ + .pack(pady=10) + + self.reemplazar_pantalla(frame) + + def mostrar_error(self): + frame = tk.Frame(self) + + tk.Label(frame, text="Error al enviar archivo", font=("Arial", 16), + fg="red").pack(pady=40) + + ttk.Button(frame, text="Volver", command=self.mostrar_home).pack(pady=10) + + self.reemplazar_pantalla(frame) + + +# ============================================================ +# MAIN +# ============================================================ + +if __name__ == "__main__": + # Iniciar servidores en background + threading.Thread(target=servidor_tcp, daemon=True).start() + threading.Thread(target=servidor_anuncios, daemon=True).start() + + app = App() + app.mainloop()