commit
ebb7ed59fc
@ -0,0 +1,357 @@
|
||||
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()
|
@ -0,0 +1,49 @@
|
||||
# Cliente y Servidor de Envío de Archivos
|
||||
|
||||
Este proyecto consiste en una aplicación cliente-servidor desarrollada en Python que permite a los usuarios enviar archivos de un cliente a un servidor.
|
||||
|
||||
## Cliente
|
||||
|
||||
El cliente de la aplicación está diseñado con una interfaz gráfica simple usando la biblioteca Tkinter de Python. Permite al usuario conectarse al servidor, explorar archivos locales y enviar archivos seleccionados al servidor.
|
||||
|
||||
### Características del Cliente:
|
||||
|
||||
- **Conexión al Servidor:** El cliente puede conectarse al servidor proporcionando la dirección IP y el puerto.
|
||||
- **Exploración de Archivos Locales:** Se puede navegar a través de los archivos locales del cliente para seleccionar un archivo para enviar al servidor.
|
||||
- **Envío de Archivos:** Una vez que se selecciona un archivo, el cliente puede enviarlo al servidor. Muestra el progreso del envío con una barra de progreso.
|
||||
|
||||
### Requisitos del Cliente:
|
||||
- Python 3.x instalado.
|
||||
- Biblioteca Tkinter (normalmente incluida con la instalación estándar de Python).
|
||||
|
||||
## Servidor
|
||||
|
||||
El servidor es una aplicación de consola simple que espera conexiones de clientes. Cuando un cliente se conecta, el servidor recibe el archivo enviado por el cliente y lo guarda en una carpeta designada.
|
||||
|
||||
### Características del Servidor:
|
||||
|
||||
- **Espera de Conexiones:** El servidor espera a que los clientes se conecten en un puerto especificado.
|
||||
- **Recepción de Archivos:** Cuando un cliente se conecta y envía un archivo, el servidor lo recibe y lo guarda en la carpeta designada.
|
||||
- **Creación de Carpetas de Usuario:** Si la carpeta de usuario correspondiente no existe en el servidor, el servidor la crea automáticamente al recibir la primera conexión de ese usuario.
|
||||
|
||||
### Requisitos del Servidor:
|
||||
- Python 3.x instalado.
|
||||
|
||||
## Uso
|
||||
|
||||
### Cliente:
|
||||
1. Ejecute el script `Cliente.py`.
|
||||
2. Ingrese la dirección IP y el puerto del servidor al que desea conectarse.
|
||||
3. Haga clic en el botón "Conectar".
|
||||
4. Use el botón "Buscar Archivos" para explorar los archivos locales y seleccione el archivo que desea enviar.
|
||||
5. Haga clic en el botón "Enviar Archivo" para enviar el archivo seleccionado al servidor.
|
||||
|
||||
### Servidor:
|
||||
1. Ejecute el script `Servidor.py`.
|
||||
2. El servidor comenzará a esperar conexiones de clientes en el puerto especificado.
|
||||
3. Los archivos enviados por los clientes se guardarán en la carpeta `usuarios` en el servidor, en una subcarpeta correspondiente al cliente.
|
||||
|
||||
## Notas Adicionales
|
||||
|
||||
- Asegúrese de que el cliente y el servidor estén en la misma red para que puedan comunicarse correctamente.
|
||||
- Siempre verifique las configuraciones de firewall y permisos de red para permitir la comunicación entre el cliente y el servidor.
|
@ -0,0 +1,72 @@
|
||||
from pyftpdlib.authorizers import DummyAuthorizer
|
||||
from pyftpdlib.handlers import FTPHandler
|
||||
from pyftpdlib.servers import FTPServer
|
||||
import os
|
||||
import time
|
||||
import string
|
||||
|
||||
class CustomFTPHandler(FTPHandler):
|
||||
def on_connect(self):
|
||||
super().on_connect()
|
||||
self.username = "user"
|
||||
print("Cliente conectado.")
|
||||
|
||||
def on_login(self, username):
|
||||
super().on_login(username)
|
||||
self.username = username
|
||||
self.user_dir = os.path.join(self.authorizer.get_home_dir(username), 'inbox')
|
||||
|
||||
# Send the default server directory path to the client
|
||||
default_server_dir = "/home/eric/ProyectoJuanjoSegundoTrimestre/usuario" # Cambiar esto al directorio predeterminado
|
||||
self.send_response("DEFAULT_DIR", default_server_dir)
|
||||
print(f"Directorio predeterminado del servidor enviado al cliente: {default_server_dir}")
|
||||
|
||||
def send_response(self, code, message):
|
||||
resp = f"{code} {message}\r\n"
|
||||
self.push(resp)
|
||||
|
||||
def on_file_sent(self, file):
|
||||
super().on_file_sent(file)
|
||||
self.broadcast_file_sent(os.path.basename(file))
|
||||
|
||||
def broadcast_file_sent(self, filename):
|
||||
print(f"File '{filename}' sent")
|
||||
|
||||
def list_files_in_user_inbox(self):
|
||||
files = []
|
||||
try:
|
||||
files = os.listdir(self.user_dir)
|
||||
except FileNotFoundError:
|
||||
pass
|
||||
return files
|
||||
|
||||
def normalize_filename(self, filename):
|
||||
valid_chars = "-_.() %s%s" % (string.ascii_letters, string.digits)
|
||||
filename = ''.join(c for c in filename if c in valid_chars)
|
||||
filename = filename[:255] # Limit filename length to 255 characters
|
||||
return filename
|
||||
|
||||
def save_file(self, filename, data):
|
||||
try:
|
||||
filename = self.normalize_filename(filename)
|
||||
with open(os.path.join(self.user_dir, filename), 'wb') as file:
|
||||
file.write(data)
|
||||
print(f"File '{filename}' saved to {self.username}'s inbox.")
|
||||
except Exception as e:
|
||||
print(f"Error saving file: {e}")
|
||||
|
||||
def run_ftp_server():
|
||||
authorizer = DummyAuthorizer()
|
||||
# Creamos un único usuario
|
||||
authorizer.add_user("user", "password", "/home/eric/ProyectoJuanjoSegundoTrimestre/usuario", perm="lradw") # Cambia "/path/to/home/directory" al directorio que desees
|
||||
|
||||
handler = CustomFTPHandler
|
||||
handler.authorizer = authorizer
|
||||
|
||||
server = FTPServer(("127.0.0.1", 12345), handler)
|
||||
server.max_cons_per_ip = 5
|
||||
|
||||
server.serve_forever()
|
||||
|
||||
if __name__ == "__main__":
|
||||
run_ftp_server()
|
Loading…
Reference in new issue