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

7 months ago
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.