350 lines
11 KiB
Python
350 lines
11 KiB
Python
|
|
"""
|
||
|
|
TRANSFERENCIA DE ARCHIVOS - SIN TUPLAS NI DICCIONARIOS
|
||
|
|
Versión ultra simplificada para explicación
|
||
|
|
"""
|
||
|
|
|
||
|
|
# ========================================
|
||
|
|
# IMPORTS
|
||
|
|
# ========================================
|
||
|
|
import socket
|
||
|
|
import threading
|
||
|
|
import tkinter as tk
|
||
|
|
import os
|
||
|
|
|
||
|
|
# ========================================
|
||
|
|
# VARIABLES GLOBALES
|
||
|
|
# ========================================
|
||
|
|
MI_IP = ""
|
||
|
|
PUERTO = 5000
|
||
|
|
BUFFER_TAMANO = 4096
|
||
|
|
ARCHIVO_A_ENVIAR = ""
|
||
|
|
IP_DESTINO = ""
|
||
|
|
|
||
|
|
# ========================================
|
||
|
|
# FUNCIONES DE RED
|
||
|
|
# ========================================
|
||
|
|
def conseguir_mi_ip():
|
||
|
|
"""Consigue la IP de esta computadora"""
|
||
|
|
try:
|
||
|
|
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
||
|
|
s.connect(("8.8.8.8", 80))
|
||
|
|
ip_numero = s.getsockname()[0]
|
||
|
|
s.close()
|
||
|
|
return ip_numero
|
||
|
|
except:
|
||
|
|
return "127.0.0.1"
|
||
|
|
|
||
|
|
def escuchar_archivos():
|
||
|
|
"""Escucha conexiones y recibe archivos"""
|
||
|
|
# Crear carpeta para archivos recibidos
|
||
|
|
if not os.path.exists("recibidos"):
|
||
|
|
os.makedirs("recibidos")
|
||
|
|
|
||
|
|
# Crear socket servidor
|
||
|
|
servidor_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||
|
|
servidor_socket.bind(("0.0.0.0", PUERTO))
|
||
|
|
servidor_socket.listen(5)
|
||
|
|
|
||
|
|
print(f"Escuchando en puerto {PUERTO}...")
|
||
|
|
|
||
|
|
while True:
|
||
|
|
# Esperar conexión
|
||
|
|
cliente_socket, direccion_cliente = servidor_socket.accept()
|
||
|
|
ip_cliente = direccion_cliente[0] # Solo tomamos la IP (no el puerto)
|
||
|
|
print(f"Conexión desde: {ip_cliente}")
|
||
|
|
|
||
|
|
# Recibir información del archivo
|
||
|
|
info_archivo = cliente_socket.recv(1024).decode()
|
||
|
|
|
||
|
|
# Separar nombre y tamaño
|
||
|
|
if "|" in info_archivo:
|
||
|
|
partes = info_archivo.split("|")
|
||
|
|
nombre_archivo = partes[0]
|
||
|
|
tamaño_archivo = int(partes[1])
|
||
|
|
|
||
|
|
# Guardar archivo
|
||
|
|
ruta_completa = "recibidos/" + nombre_archivo
|
||
|
|
|
||
|
|
# Evitar sobrescribir archivos
|
||
|
|
contador = 1
|
||
|
|
while os.path.exists(ruta_completa):
|
||
|
|
nombre_base = nombre_archivo.split(".")[0]
|
||
|
|
extension = nombre_archivo.split(".")[-1]
|
||
|
|
ruta_completa = f"recibidos/{nombre_base}_{contador}.{extension}"
|
||
|
|
contador += 1
|
||
|
|
|
||
|
|
# Abrir archivo para escribir
|
||
|
|
archivo_destino = open(ruta_completa, "wb")
|
||
|
|
|
||
|
|
# Recibir datos en partes
|
||
|
|
bytes_recibidos = 0
|
||
|
|
while bytes_recibidos < tamaño_archivo:
|
||
|
|
datos = cliente_socket.recv(BUFFER_TAMANO)
|
||
|
|
archivo_destino.write(datos)
|
||
|
|
bytes_recibidos += len(datos)
|
||
|
|
|
||
|
|
# Cerrar archivo
|
||
|
|
archivo_destino.close()
|
||
|
|
|
||
|
|
print(f"Archivo guardado: {ruta_completa}")
|
||
|
|
|
||
|
|
# Enviar confirmación
|
||
|
|
cliente_socket.send(b"OK")
|
||
|
|
|
||
|
|
# Cerrar conexión
|
||
|
|
cliente_socket.close()
|
||
|
|
|
||
|
|
def mandar_archivo(ruta, ip):
|
||
|
|
"""Envía un archivo a otra computadora"""
|
||
|
|
# Verificar que el archivo existe
|
||
|
|
if not os.path.exists(ruta):
|
||
|
|
return False
|
||
|
|
|
||
|
|
# Obtener información del archivo
|
||
|
|
nombre_archivo = os.path.basename(ruta)
|
||
|
|
tamaño_archivo = os.path.getsize(ruta)
|
||
|
|
|
||
|
|
try:
|
||
|
|
# Crear socket cliente
|
||
|
|
cliente_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||
|
|
cliente_socket.settimeout(10)
|
||
|
|
|
||
|
|
# Conectar al destino
|
||
|
|
cliente_socket.connect((ip, PUERTO))
|
||
|
|
|
||
|
|
# Enviar información del archivo
|
||
|
|
mensaje_info = nombre_archivo + "|" + str(tamaño_archivo)
|
||
|
|
cliente_socket.send(mensaje_info.encode())
|
||
|
|
|
||
|
|
# Abrir y enviar archivo
|
||
|
|
archivo_origen = open(ruta, "rb")
|
||
|
|
|
||
|
|
while True:
|
||
|
|
datos = archivo_origen.read(BUFFER_TAMANO)
|
||
|
|
if not datos:
|
||
|
|
break
|
||
|
|
cliente_socket.send(datos)
|
||
|
|
|
||
|
|
# Cerrar archivo
|
||
|
|
archivo_origen.close()
|
||
|
|
|
||
|
|
# Esperar confirmación
|
||
|
|
respuesta = cliente_socket.recv(1024)
|
||
|
|
cliente_socket.close()
|
||
|
|
|
||
|
|
if respuesta == b"OK":
|
||
|
|
return True
|
||
|
|
else:
|
||
|
|
return False
|
||
|
|
|
||
|
|
except Exception as error:
|
||
|
|
print(f"Error: {error}")
|
||
|
|
return False
|
||
|
|
|
||
|
|
def buscar_computadoras():
|
||
|
|
"""Busca otras computadoras en la red"""
|
||
|
|
computadoras_encontradas = []
|
||
|
|
|
||
|
|
# Obtener base de IP
|
||
|
|
partes_ip = MI_IP.split(".")
|
||
|
|
if len(partes_ip) == 4:
|
||
|
|
ip_base = partes_ip[0] + "." + partes_ip[1] + "." + partes_ip[2]
|
||
|
|
|
||
|
|
# Probar primeras 20 IPs
|
||
|
|
for ultimo_numero in range(1, 21):
|
||
|
|
ip_completa = ip_base + "." + str(ultimo_numero)
|
||
|
|
|
||
|
|
# Saltar nuestra propia IP
|
||
|
|
if ip_completa == MI_IP:
|
||
|
|
continue
|
||
|
|
|
||
|
|
# Intentar conectar
|
||
|
|
try:
|
||
|
|
s = socket.socket()
|
||
|
|
s.settimeout(0.2)
|
||
|
|
s.connect((ip_completa, PUERTO))
|
||
|
|
computadoras_encontradas.append(ip_completa)
|
||
|
|
s.close()
|
||
|
|
except:
|
||
|
|
pass
|
||
|
|
|
||
|
|
return computadoras_encontradas
|
||
|
|
|
||
|
|
# ========================================
|
||
|
|
# INTERFAZ GRÁFICA
|
||
|
|
# ========================================
|
||
|
|
class AplicacionTransferencia:
|
||
|
|
def __init__(self):
|
||
|
|
# Crear ventana principal
|
||
|
|
self.ventana_principal = tk.Tk()
|
||
|
|
self.ventana_principal.title("Enviar Archivos")
|
||
|
|
self.ventana_principal.geometry("400x450")
|
||
|
|
|
||
|
|
# Variables de la aplicación
|
||
|
|
global MI_IP
|
||
|
|
MI_IP = conseguir_mi_ip()
|
||
|
|
|
||
|
|
# Lista para equipos encontrados
|
||
|
|
self.lista_equipos = []
|
||
|
|
|
||
|
|
# Crear interfaz
|
||
|
|
self.crear_interfaz_grafica()
|
||
|
|
|
||
|
|
# Iniciar servidor en segundo plano
|
||
|
|
hilo_servidor = threading.Thread(target=escuchar_archivos)
|
||
|
|
hilo_servidor.daemon = True
|
||
|
|
hilo_servidor.start()
|
||
|
|
|
||
|
|
def crear_interfaz_grafica(self):
|
||
|
|
"""Crea todos los elementos visuales"""
|
||
|
|
|
||
|
|
# Título
|
||
|
|
etiqueta_titulo = tk.Label(self.ventana_principal,
|
||
|
|
text="Enviar Archivos",
|
||
|
|
font=("Arial", 18))
|
||
|
|
etiqueta_titulo.pack(pady=20)
|
||
|
|
|
||
|
|
# Mostrar IP local
|
||
|
|
etiqueta_ip = tk.Label(self.ventana_principal,
|
||
|
|
text="Tu IP: " + MI_IP,
|
||
|
|
font=("Arial", 12))
|
||
|
|
etiqueta_ip.pack(pady=10)
|
||
|
|
|
||
|
|
# Línea separadora
|
||
|
|
linea = tk.Frame(self.ventana_principal, height=2, bg="gray")
|
||
|
|
linea.pack(fill="x", padx=20, pady=10)
|
||
|
|
|
||
|
|
# Botón para buscar
|
||
|
|
boton_buscar = tk.Button(self.ventana_principal,
|
||
|
|
text="Buscar Equipos",
|
||
|
|
command=self.buscar,
|
||
|
|
font=("Arial", 12))
|
||
|
|
boton_buscar.pack(pady=10)
|
||
|
|
|
||
|
|
# Lista para mostrar equipos
|
||
|
|
self.lista_widget = tk.Listbox(self.ventana_principal, height=6)
|
||
|
|
self.lista_widget.pack(pady=10, padx=20, fill="x")
|
||
|
|
|
||
|
|
# Botón para seleccionar archivo
|
||
|
|
boton_archivo = tk.Button(self.ventana_principal,
|
||
|
|
text="Seleccionar Archivo",
|
||
|
|
command=self.seleccionar,
|
||
|
|
font=("Arial", 12))
|
||
|
|
boton_archivo.pack(pady=10)
|
||
|
|
|
||
|
|
# Etiqueta para información
|
||
|
|
self.etiqueta_info = tk.Label(self.ventana_principal,
|
||
|
|
text="Esperando...",
|
||
|
|
font=("Arial", 10))
|
||
|
|
self.etiqueta_info.pack(pady=5)
|
||
|
|
|
||
|
|
# Botón para enviar
|
||
|
|
self.boton_enviar = tk.Button(self.ventana_principal,
|
||
|
|
text="ENVIAR",
|
||
|
|
command=self.enviar,
|
||
|
|
font=("Arial", 12),
|
||
|
|
state="disabled")
|
||
|
|
self.boton_enviar.pack(pady=10)
|
||
|
|
|
||
|
|
# Etiqueta para estado
|
||
|
|
self.etiqueta_estado = tk.Label(self.ventana_principal,
|
||
|
|
text="",
|
||
|
|
font=("Arial", 10))
|
||
|
|
self.etiqueta_estado.pack(pady=10)
|
||
|
|
|
||
|
|
def buscar(self):
|
||
|
|
"""Busca otros equipos en la red"""
|
||
|
|
# Limpiar lista
|
||
|
|
self.lista_widget.delete(0, tk.END)
|
||
|
|
self.etiqueta_info.config(text="Buscando...")
|
||
|
|
|
||
|
|
# Buscar computadoras
|
||
|
|
self.lista_equipos = buscar_computadoras()
|
||
|
|
|
||
|
|
# Mostrar resultados
|
||
|
|
if len(self.lista_equipos) > 0:
|
||
|
|
for equipo in self.lista_equipos:
|
||
|
|
self.lista_widget.insert(tk.END, equipo)
|
||
|
|
self.etiqueta_info.config(text=f"Encontrados: {len(self.lista_equipos)}")
|
||
|
|
else:
|
||
|
|
self.etiqueta_info.config(text="No se encontraron equipos")
|
||
|
|
|
||
|
|
def seleccionar(self):
|
||
|
|
"""Permite seleccionar un archivo"""
|
||
|
|
# Importar aquí para no cargarlo al inicio
|
||
|
|
from tkinter import filedialog
|
||
|
|
|
||
|
|
archivo = filedialog.askopenfilename(title="Elegir archivo")
|
||
|
|
|
||
|
|
if archivo:
|
||
|
|
global ARCHIVO_A_ENVIAR
|
||
|
|
ARCHIVO_A_ENVIAR = archivo
|
||
|
|
|
||
|
|
nombre = os.path.basename(archivo)
|
||
|
|
tamaño = os.path.getsize(archivo)
|
||
|
|
|
||
|
|
self.etiqueta_info.config(text=f"Listo: {nombre}")
|
||
|
|
self.boton_enviar.config(state="normal")
|
||
|
|
|
||
|
|
def enviar(self):
|
||
|
|
"""Envía el archivo seleccionado"""
|
||
|
|
# Obtener selección de la lista
|
||
|
|
indices_seleccionados = self.lista_widget.curselection()
|
||
|
|
|
||
|
|
if len(indices_seleccionados) == 0:
|
||
|
|
self.etiqueta_estado.config(text="Error: Selecciona un equipo")
|
||
|
|
return
|
||
|
|
|
||
|
|
indice = indices_seleccionados[0]
|
||
|
|
|
||
|
|
# Verificar índice válido
|
||
|
|
if indice < 0 or indice >= len(self.lista_equipos):
|
||
|
|
self.etiqueta_estado.config(text="Error: Equipo no válido")
|
||
|
|
return
|
||
|
|
|
||
|
|
# Obtener IP de destino
|
||
|
|
global IP_DESTINO
|
||
|
|
IP_DESTINO = self.lista_equipos[indice]
|
||
|
|
|
||
|
|
# Verificar archivo seleccionado
|
||
|
|
if not ARCHIVO_A_ENVIAR:
|
||
|
|
self.etiqueta_estado.config(text="Error: No hay archivo")
|
||
|
|
return
|
||
|
|
|
||
|
|
# Cambiar estado
|
||
|
|
self.etiqueta_estado.config(text="Enviando...")
|
||
|
|
self.boton_enviar.config(state="disabled")
|
||
|
|
|
||
|
|
# Enviar en segundo plano
|
||
|
|
hilo_envio = threading.Thread(target=self.enviar_en_segundo_plano)
|
||
|
|
hilo_envio.daemon = True
|
||
|
|
hilo_envio.start()
|
||
|
|
|
||
|
|
def enviar_en_segundo_plano(self):
|
||
|
|
"""Envía el archivo sin bloquear la interfaz"""
|
||
|
|
resultado = mandar_archivo(ARCHIVO_A_ENVIAR, IP_DESTINO)
|
||
|
|
|
||
|
|
# Actualizar interfaz
|
||
|
|
if resultado:
|
||
|
|
self.etiqueta_estado.config(text="¡Archivo enviado!")
|
||
|
|
else:
|
||
|
|
self.etiqueta_estado.config(text="Error al enviar")
|
||
|
|
|
||
|
|
self.boton_enviar.config(state="normal")
|
||
|
|
|
||
|
|
def iniciar(self):
|
||
|
|
"""Comienza la aplicación"""
|
||
|
|
self.ventana_principal.mainloop()
|
||
|
|
|
||
|
|
# ========================================
|
||
|
|
# PROGRAMA PRINCIPAL
|
||
|
|
# ========================================
|
||
|
|
if __name__ == "__main__":
|
||
|
|
print("Iniciando aplicación...")
|
||
|
|
print(f"IP Local: {MI_IP}")
|
||
|
|
print(f"Puerto: {PUERTO}")
|
||
|
|
|
||
|
|
# Crear y ejecutar aplicación
|
||
|
|
app = AplicacionTransferencia()
|
||
|
|
app.iniciar()
|