Ya ahora está pulentopolis
parent
beb8abc88a
commit
5cf27fb016
|
|
@ -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(), ('<broadcast>', 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()
|
||||||
Loading…
Reference in New Issue