From 1d8affbb078dd83af9622ac7356d0cbca37e1a05 Mon Sep 17 00:00:00 2001 From: Kah Kian Fong Date: Mon, 13 Mar 2023 20:34:15 +0800 Subject: [PATCH] Added serverfile for ftp server file storage, added clientfile for ftp client file storage, able to list, upload, download and rename --- .idea/.gitignore | 3 ++ .idea/Python_FTP.iml | 8 ++++ .idea/inspectionProfiles/Project_Default.xml | 15 ++++++ .../inspectionProfiles/profiles_settings.xml | 6 +++ .idea/misc.xml | 4 ++ .idea/modules.xml | 8 ++++ .idea/vcs.xml | 6 +++ client.py | 31 +++++++++--- server.py | 48 ++++++++++++------- 9 files changed, 106 insertions(+), 23 deletions(-) create mode 100644 .idea/.gitignore create mode 100644 .idea/Python_FTP.iml create mode 100644 .idea/inspectionProfiles/Project_Default.xml create mode 100644 .idea/inspectionProfiles/profiles_settings.xml create mode 100644 .idea/misc.xml create mode 100644 .idea/modules.xml create mode 100644 .idea/vcs.xml diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..26d3352 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,3 @@ +# Default ignored files +/shelf/ +/workspace.xml diff --git a/.idea/Python_FTP.iml b/.idea/Python_FTP.iml new file mode 100644 index 0000000..8437fe6 --- /dev/null +++ b/.idea/Python_FTP.iml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml new file mode 100644 index 0000000..5ef7adc --- /dev/null +++ b/.idea/inspectionProfiles/Project_Default.xml @@ -0,0 +1,15 @@ + + + + \ No newline at end of file diff --git a/.idea/inspectionProfiles/profiles_settings.xml b/.idea/inspectionProfiles/profiles_settings.xml new file mode 100644 index 0000000..105ce2d --- /dev/null +++ b/.idea/inspectionProfiles/profiles_settings.xml @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..087ee2c --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..f335361 --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..35eb1dd --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/client.py b/client.py index f89e170..d0f5b8f 100644 --- a/client.py +++ b/client.py @@ -1,16 +1,18 @@ import os import socket +CLIENT_FILE = "clientfile" + # This prints 1 line at first, then the whole list after running the command again def handle_list(conn, args): # Show list of files received from server in response to LIST command # Response is a multi-line string - response = conn.recv(1024).decode('latin-1').strip() - print(response) + response = conn.recv(4096).decode('latin-1').strip() + print(response) # Check for multi-line response while response.startswith("1"): - response = conn.recv(1024).decode("latin-1") + response = conn.recv(4096).decode("latin-1") print(response) @@ -24,18 +26,32 @@ def handle_quit(conn, args): return True -def handle_dwld(conn, args): +def handle_DWLD(conn, args): + # send command over filename = args conn.sendall(f"DWLD {filename}\r".encode()) - + os.chdir(os.path.abspath(CLIENT_FILE)) filedata = conn.recv(1024) print(filedata) with open(filename, "wb") as f: f.write(filedata) + os.chdir("../") print("File downloaded successfully") + +# def handle_dwld(conn, args): +# filename = args +# conn.sendall(f"DWLD {filename}\r".encode()) + +# filedata = conn.recv(1024) +# print(filedata) +# with open(filename, "wb") as f: +# f.write(filedata) +# print("File downloaded successfully") + def handle_UPLD(conn, args): filename = args + os.chdir(os.path.abspath(CLIENT_FILE)) if not os.path.exists(filename): print("File does not exist") else: @@ -44,8 +60,9 @@ def handle_UPLD(conn, args): file_size = os.path.getsize(filename) conn.sendall(f"UPLD {filename} {file_size}\r".encode()) conn.sendall(filedata) - response = conn.recv(1024).decode().strip() + response = conn.recv(4096).decode().strip() print(response) + os.chdir("../") def user_input(): # Get user input @@ -82,7 +99,7 @@ def ftp_cient(host, port): handle_quit(sock, args) break elif command.upper() == "DWLD": - handle_dwld(sock, args) + handle_DWLD(sock, args) elif command.upper() == "UPLD": handle_UPLD(sock, args) elif command.upper() == "DELF": diff --git a/server.py b/server.py index 08c70d2..a9269e8 100644 --- a/server.py +++ b/server.py @@ -7,9 +7,12 @@ import struct import time BUFFER_SIZE = 1024 +SERVER_FILE = "serverfile" def handle_list(conn, args): #conn.send(b'150 Opening ASCII mode data connection for file list.\n') + #home_directory = os.path.expanduser('~') + os.chdir(os.path.abspath(SERVER_FILE)) files = os.listdir(os.getcwd()) for file in files: file_info = os.stat(file) @@ -18,64 +21,71 @@ def handle_list(conn, args): file_time = file_info.st_mtime file_date = time.strftime('%b %d %H:%M', time.gmtime(file_time)) file_name = file.encode('utf-8') + b'\r\n' - conn.send(file_mode.encode('utf-8') + b' 1 user user ' + str(file_size).encode('utf-8') + b' ' + file_date.encode('utf-8') + b' ' + file_name) + conn.sendall(file_mode.encode('utf-8') + b' 1 user user ' + str(file_size).encode('utf-8') + b' ' + file_date.encode('utf-8') + b' ' + file_name) if not files: - conn.send(b'226 No files in directory.\n') - conn.send(b'226 Transfer complete.\n') + conn.sendall(b'226 No files in directory.\n') + os.chdir("../") + conn.sendall(b'226 Transfer complete.\n') def handle_upload(conn, args): filename = args[1] filesize = int(args[2]) + os.chdir(os.path.abspath(SERVER_FILE)) print(f'Uploading {filename} ({filesize} bytes)') with open(filename, 'wb') as f: data = conn.recv(4096) f.write(data) - conn.send(b'done') + os.chdir("../") + conn.sendall(b'Upload done') def handle_download(conn, args): filename = args[1] + os.chdir(os.path.abspath(SERVER_FILE)) filesize = os.path.getsize(filename) #conn.send(struct.pack('i', filesize)) with open(filename, 'rb') as f: data = f.read(4096) while data: - conn.send(data) + conn.sendall(data) data = f.read(4096) - conn.send(b'done') + os.chdir("../") + conn.sendall(b'Download done') def handle_delete(conn, args): filename = args[1] os.remove(filename) - conn.send(b'done') + conn.sendall(b'Delete done') def handle_rename(conn, args): + os.chdir(os.path.abspath(SERVER_FILE)) old_filename = args[1] new_filename = args[2] os.rename(old_filename, new_filename) - conn.send(b'done') + os.chdir("../") + conn.sendall(f"completed".encode('utf-8')) def handle_quit(conn, args): - conn.send(b'done') + conn.sendall(b'Quitting') conn.close() return True def handle_user(conn, args): - conn.send(b'230 Login successful.\n') + conn.sendall(b'230 Login successful.\n') def handle_pwd(conn, args): current_dir = os.getcwd() - conn.send(f'257 "{current_dir}" is the current directory.\n'.encode()) + conn.sendall(f'257 "{current_dir}" is the current directory.\n'.encode()) handle_list(conn, args) def handle_port(conn, args): - conn.send(b'200 OK\n') + conn.sendall(b'200 OK\n') commands = { 'LIST': handle_list, @@ -86,15 +96,19 @@ commands = { 'QUIT': handle_quit, 'USER': handle_user, 'PWD': handle_pwd, - 'TYPE': lambda conn, args: conn.send(b'200 OK\n'), + 'TYPE': lambda conn, args: conn.sendall(b'200 OK\n'), 'PORT': handle_port, - 'CDUP': lambda conn, args: conn.send(b'200 OK\n'), + 'CDUP': lambda conn, args: conn.sendall(b'200 OK\n'), } def handle_connection(conn): - conn.send(b'220 Welcome to the FTP server.\n') + conn.send(b'220 Welcome to the FTP server.\nList of executable commands:\nLIST: List files\nUPLD : ' + b'Upload file\nDWLD : Download file\nDELF : Delete file\nRNTO ' + b': Rename file\nQUIT: Exit') + while True: + data = conn.recv(BUFFER_SIZE).decode() print(f'Server received: {data}') if not data: @@ -104,10 +118,12 @@ def handle_connection(conn): print(f'Command: {command}') if command in commands: if commands == handle_quit: + conn.sendall(b'Closing Connection') + conn.close() break commands[command](conn, args) else: - conn.send(b'Invalid command.\n') + conn.sendall(b'Invalid command.\n') # For FTP client testing #handle_pwd(conn, [])