You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

358 lines
16 KiB

import tkinter as tk
from tkinter import ttk, filedialog
import os
import socket
import threading
import time
class FTPClient:
def __init__(self):
self.server_dir = ""
self.root = tk.Tk()
self.root.title("Cliente de Archivos")
self.root.geometry("950x600")
# Valores predeterminados para la dirección IP y el puerto
default_ip = "127.0.0.1"
default_port = "12345"
# Frame para la conexión
self.connection_frame = tk.Frame(self.root)
self.connection_frame.pack(pady=10)
self.con_frame = tk.LabelFrame(self.connection_frame, text="Conexion")
self.con_frame.grid(row=0, column=0, padx=10, pady=5)
self.label_ip = tk.Label(self.con_frame, text="IP del Servidor:")
self.label_ip.grid(row=0, column=0, padx=5)
self.entry_ip = tk.Entry(self.con_frame, width=20)
self.entry_ip.insert(0, default_ip)
self.entry_ip.grid(row=0, column=1, padx=5)
self.label_port = tk.Label(self.con_frame, text="Puerto:")
self.label_port.grid(row=0, column=2, padx=5)
self.entry_port = tk.Entry(self.con_frame, width=10)
self.entry_port.insert(0, default_port)
self.entry_port.grid(row=0, column=3, padx=5)
self.button_connect = tk.Button(self.con_frame, text="Conectar", width=10, command=self.connect_to_server)
self.button_connect.grid(row=0, column=4, padx=5)
self.button_disconnect = tk.Button(self.con_frame, text="Desconectar", width=10, state=tk.DISABLED, command=self.disconnect_from_server)
self.button_disconnect.grid(row=0, column=5, padx=5)
# Frame principal para los archivos locales y directorios del servidor
self.main_frame = tk.Frame(self.root)
self.main_frame.pack(fill="both", expand=True, padx=20, pady=5)
# Frame para la configuración de la carpeta local del cliente
self.config_frame = tk.LabelFrame(self.main_frame, text="Configuración de Carpeta Local")
self.config_frame.pack(fill="x", expand=True, padx=20, pady=5, anchor="center") # Alinear al centro
self.label_local_folder = tk.Label(self.config_frame, text="Carpeta Local:")
self.label_local_folder.grid(row=0, column=0, padx=20, sticky="e")
self.entry_local_folder = tk.Entry(self.config_frame, width=50)
self.entry_local_folder.grid(row=0, column=1, padx=20, sticky="w")
self.button_browse = tk.Button(self.config_frame, text="Explorar", width=10, command=self.browse_local_folder)
self.button_browse.grid(row=0, column=2, padx=20, pady=10, sticky="e")
self.button_apply = tk.Button(self.config_frame, text="Aplicar", width=10, command=self.apply_local_folder)
self.button_apply.grid(row=0, column=3, padx=5, pady=10, sticky="w")
# Frame para los botones de navegación de archivos locales
self.local_nav_frame = tk.Frame(self.main_frame)
self.local_nav_frame.pack(side="left", padx=5)
self.button_up = tk.Button(self.local_nav_frame, text="Subir", command=self.go_up)
self.button_up.pack(side="top", pady=5)
self.button_open = tk.Button(self.local_nav_frame, text="Abrir", command=self.open_directory)
self.button_open.pack(side="top", pady=5)
# Frame para los botones de navegación de archivos del servidor
self.server_nav_frame = tk.Frame(self.main_frame)
self.server_nav_frame.pack(side="right", padx=5)
self.server_button_up = tk.Button(self.server_nav_frame, text="Subir", command=self.go_up_server)
self.server_button_up.pack(side="top", pady=5)
self.server_button_open = tk.Button(self.server_nav_frame, text="Abrir", command=self.open_directory_server)
self.server_button_open.pack(side="top", pady=5)
# Frame para todos los archivos
self.files_frame = tk.Frame(self.main_frame)
self.files_frame.pack(fill="both", expand=True, padx=20, pady=5)
# Frame para los archivos locales
self.local_files_frame = tk.LabelFrame(self.files_frame, text="Archivos Locales")
self.local_files_frame.pack(side="left", fill="both", expand=True)
self.local_files_list = tk.Listbox(self.local_files_frame, width=50, height=20)
self.local_files_list.pack(side="left", fill="both", expand=True)
self.local_files_scrollbar = ttk.Scrollbar(self.local_files_frame, orient="vertical")
self.local_files_scrollbar.config(command=self.local_files_list.yview)
self.local_files_scrollbar.pack(side="right", fill="y")
self.local_files_list.config(yscrollcommand=self.local_files_scrollbar.set)
# Frame para los archivos del servidor
self.server_files_frame = tk.LabelFrame(self.files_frame, text="Archivos del Servidor")
self.server_files_frame.pack(side="right", fill="both", expand=True)
self.server_files_list = tk.Listbox(self.server_files_frame, width=50, height=20)
self.server_files_list.pack(side="left", fill="both", expand=True)
self.server_files_scrollbar = ttk.Scrollbar(self.server_files_frame, orient="vertical")
self.server_files_scrollbar.config(command=self.server_files_list.yview)
self.server_files_scrollbar.pack(side="right", fill="y")
self.server_files_list.config(yscrollcommand=self.server_files_scrollbar.set)
# Frame para el botón y la ProgressBar
self.upload_frame = tk.Frame(self.main_frame)
self.upload_frame.pack(side="left", fill="both", pady=10)
self.button_send_file = tk.Button(self.upload_frame, text="Enviar Archivo", command=self.send_selected_file)
self.button_send_file.pack(side="left", padx=10)
self.entry_server_path = tk.Entry(self.upload_frame, width=50)
self.entry_server_path.pack(side="left", pady=5)
self.progress_bar = ttk.Progressbar(self.upload_frame, orient="horizontal", length=200, mode="determinate")
self.progress_bar.pack(side="right", padx=10)
self.timer_label = tk.Label(self.upload_frame, text="")
self.timer_label.pack()
self.client_socket = None
self.monitor_thread = None # Hilo para monitorear el buzón de entrada
def connect_to_server(self):
server = self.entry_ip.get()
port = int(self.entry_port.get())
self.client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
try:
print("Conectando al servidor...")
self.client_socket.settimeout(10) # Establecer un tiempo de espera de 10 segundos para la respuesta del servidor
self.client_socket.connect((server, port))
credentials = "user:password"
self.client_socket.send(credentials.encode())
print(f"Conectado al servidor {server}:{port}")
# Esperar y recibir el mensaje de bienvenida del servidor
response = self.receive_response(self.client_socket)
print("Mensaje de bienvenida del servidor:", response.decode("utf-8"))
# Si el mensaje indica que el servidor está listo, continuar con la configuración
if response.startswith(b"pyftpdlib"):
# Enviar comando para obtener el directorio del servidor
self.send_data(b"PWD", self.client_socket)
server_dir_response = self.receive_response(self.client_socket)
print("Respuesta del servidor al solicitar el directorio:", server_dir_response.decode("utf-8"))
default_server_dir = server_dir_response.decode("utf-8").split('"')[1] # Extraer el directorio del servidor de la respuesta
print(f"Directorio predeterminado del servidor: {default_server_dir}")
self.update_default_server_dir(default_server_dir) # Actualizar la interfaz con el directorio predeterminado del servidor
# Restaurar el tiempo de espera del socket a 5 segundos
self.client_socket.settimeout(5)
self.button_connect.config(state=tk.DISABLED)
self.button_disconnect.config(state=tk.NORMAL)
self.monitor_thread = threading.Thread(target=self.monitor_inbox)
self.monitor_thread.start() # Iniciar el hilo de monitoreo del buzón de entrada
else:
print("Respuesta inesperada del servidor:", response.decode("utf-8"))
except socket.timeout:
print("Conexión agotada. Por favor, verifique la IP y el puerto del servidor.")
except Exception as e:
print(f"Error al conectar al servidor: {e}")
def disconnect_from_server(self):
if self.client_socket:
self.client_socket.close()
print("Disconnected from server.")
self.button_connect.config(state=tk.NORMAL)
self.button_disconnect.config(state=tk.DISABLED)
def send_selected_file(self):
selected_file = self.local_files_list.get(tk.ACTIVE)
full_path = os.path.join(self.entry_local_folder.get(), selected_file)
if os.path.isfile(full_path):
recipient = "" # Introduce el destinatario si es necesario
threading.Thread(target=self.upload_file, args=(full_path, recipient)).start() # Ejecutar la función de carga en un hilo separado
else:
print("Please select a file to send.")
def upload_file(self, filename, recipient):
try:
with open(filename, 'rb') as file:
self.send_data(b'SEND_FILE', self.client_socket)
self.send_data(recipient.encode('utf-8'), self.client_socket)
self.send_file(filename, self.client_socket)
print(f"File '{filename}' uploaded successfully to {recipient}")
except Exception as e:
print(f"Error uploading file: {e}")
def send_file(self, filename, client_socket):
with open(filename, 'rb') as file:
filename_bytes = os.path.basename(filename).encode('utf-8')
self.send_data(filename_bytes, client_socket)
file_size = os.path.getsize(filename)
self.send_data(str(file_size).encode('utf-8'), client_socket)
sent_bytes = 0
while True:
chunk = file.read(1024)
if not chunk:
break
client_socket.sendall(chunk)
sent_bytes += len(chunk)
# Actualizar la ProgressBar
progress = min(int(sent_bytes / file_size * 100), 100)
self.progress_bar['value'] = progress
self.root.update_idletasks() # Actualizar la interfaz gráfica
def monitor_inbox(self):
while True:
self.send_data(b'CHECK_INBOX', self.client_socket)
data = self.receive_response(self.client_socket)
if data:
filename = data.decode('utf-8')
self.receive_file(filename)
time.sleep(300) # Check every 5 minutes
def receive_file(self, filename):
try:
with open(filename, 'wb') as file:
filename_bytes = filename.encode('utf-8')
self.send_data(b'RETRIEVE_FILE', self.client_socket)
self.send_data(filename_bytes, self.client_socket)
file_size = int(self.receive_response(self.client_socket).decode('utf-8'))
received_bytes = 0
while received_bytes < file_size:
chunk = self.client_socket.recv(1024)
if not chunk:
break
file.write(chunk)
received_bytes += len(chunk)
print(f"File '{filename}' downloaded successfully")
except Exception as e:
print(f"Error receiving file: {e}")
def receive_response(self, client_socket):
try:
print("Esperando respuesta del servidor...")
response_data = b'' # Inicializar un buffer para almacenar los datos recibidos
# Recibir los datos hasta que se encuentre el delimitador especial
while True:
chunk = client_socket.recv(1024)
if not chunk:
break
response_data += chunk
if b'\n' in chunk:
break
response_str = response_data # Devolver los datos recibidos tal cual
print(f"Respuesta del servidor recibida: {response_str}")
return response_str
except Exception as e:
print(f"Error al recibir respuesta del servidor: {e}")
return None
def send_data(self, data, client_socket):
data_size = len(data)
data_size_bytes = data_size.to_bytes(4, byteorder='big')
client_socket.sendall(data_size_bytes)
total_sent = 0
while total_sent < data_size:
sent = client_socket.send(data[total_sent:])
if sent == 0:
raise RuntimeError("Connection closed unexpectedly.")
total_sent += sent
def browse_local_folder(self):
folder_path = filedialog.askdirectory()
self.entry_local_folder.delete(0, tk.END)
self.entry_local_folder.insert(0, folder_path)
self.update_local_files_list()
def apply_local_folder(self):
folder_path = self.entry_local_folder.get()
if os.path.isdir(folder_path):
self.update_local_files_list()
else:
print("Invalid directory path.")
def go_up(self):
current_path = self.entry_local_folder.get()
parent_path = os.path.dirname(current_path)
if os.path.isdir(parent_path):
self.entry_local_folder.delete(0, tk.END)
self.entry_local_folder.insert(0, parent_path)
self.update_local_files_list()
def open_directory(self):
selected_path = self.local_files_list.get(tk.ACTIVE)
full_path = os.path.join(self.entry_local_folder.get(), selected_path)
if os.path.isdir(full_path):
self.entry_local_folder.delete(0, tk.END)
self.entry_local_folder.insert(0, full_path)
self.update_local_files_list()
def go_up_server(self):
current_path = self.entry_server_folder.get()
parent_path = os.path.dirname(current_path)
if parent_path:
self.entry_server_folder.delete(0, tk.END)
self.entry_server_folder.insert(0, parent_path)
self.update_server_files_list()
def open_directory_server(self):
selected_path = self.server_files_list.get(tk.ACTIVE)
full_path = os.path.join(self.entry_server_folder.get(), selected_path)
if os.path.isdir(full_path):
self.entry_server_folder.delete(0, tk.END)
self.entry_server_folder.insert(0, full_path)
self.update_server_files_list()
def update_local_files_list(self):
folder_path = self.entry_local_folder.get()
self.local_files_list.delete(0, tk.END)
if os.path.isdir(folder_path):
files = os.listdir(folder_path)
for file in files:
self.local_files_list.insert(tk.END, file)
def update_default_server_dir(self, directory):
# Actualizar el atributo del directorio del servidor
self.server_dir = directory
# Limpiar la lista de archivos del servidor
self.server_files_list.delete(0, tk.END)
# Obtener la lista de archivos en el nuevo directorio del servidor
self.send_data(b'LIST_FILES', self.client_socket)
self.send_data(directory.encode('utf-8'), self.client_socket)
files_data = self.receive_response(self.client_socket)
# Decodificar los datos recibidos y agregar cada archivo a la lista
files = files_data.decode('utf-8').split('\n')
for file in files:
self.server_files_list.insert(tk.END, file)
def run(self):
self.root.mainloop()
def main():
client = FTPClient()
client.run()
if __name__ == "__main__":
main()

Powered by INFORMATICA.FP.EDU.ES.