Try the HW5 code out?

This commit is contained in:
Charles Descamps 2025-04-21 18:59:31 -07:00
parent cbcb35a158
commit 3206565d55
2 changed files with 136 additions and 5 deletions

View file

@ -1,3 +1,4 @@
import os
import socket import socket
import sys import sys
import select import select
@ -15,13 +16,25 @@ def main():
SERVER_HOST = sys.argv[1] SERVER_HOST = sys.argv[1]
SERVER_PORT = int(sys.argv[2]) SERVER_PORT = int(sys.argv[2])
# Prompt user for a local directory path for file operations
while True:
local_path = input("Enter a local directory path for sending/receiving files: ").strip()
if os.path.isdir(local_path):
print(f"Using directory: {local_path}")
break
else:
print("Invalid directory. Please enter a valid path.")
# create a socket object # create a socket object
client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
try: try:
# connect to the server # connect to the server
client_socket.connect((SERVER_HOST, SERVER_PORT)) client_socket.connect((SERVER_HOST, SERVER_PORT))
print(f"Connected to chat server at {SERVER_HOST}:{SERVER_PORT}") print(f"Connected to chat server at {SERVER_HOST}:{SERVER_PORT}")
# Send the local path to the server
client_socket.send(f"SET_PATH {local_path}".encode('utf-8'))
while True: while True:
# use select to wait for either server messages or user input # use select to wait for either server messages or user input
read_sockets, _, _ = select.select([client_socket, sys.stdin], [], []) read_sockets, _, _ = select.select([client_socket, sys.stdin], [], [])
@ -33,8 +46,35 @@ def main():
if not server_message: if not server_message:
print("Disconnected from server") print("Disconnected from server")
return return
print(f"\n{server_message}") if server_message.startswith("FILE_REQUEST"):
print("> ", end="", flush=True) # Handle file request
_, sending_username, filename = server_message.split()
file_path = os.path.join(local_path, filename)
if os.path.isfile(file_path):
file_size = os.path.getsize(file_path)
with open(file_path, "rb") as f:
file_bytes = f.read()
filetype = "File"
client_socket.send(
f"@{sending_username}@CLIENT -f {filename} {filetype} {file_size} {file_bytes.decode('latin1')} ENDFILE".encode('utf-8')
)
else:
client_socket.send(
f"@{sending_username}@CLIENT -f {filename} NOTFOUND".encode('utf-8')
)
elif server_message.startswith("FILE_TRANSFER"):
# Handle file transfer
_, sending_username, filename, filetype, filelength = server_message.split()
file_bytes = client_socket.recv(int(filelength))
end_marker = client_socket.recv(BUFFER_SIZE).decode('utf-8')
if end_marker == "ENDFILE":
file_path = os.path.join(local_path, filename)
with open(file_path, "wb") as f:
f.write(file_bytes)
print(f"Received file '{filename}' from {sending_username}.")
else:
print(f"\n{server_message}")
print("> ", end="", flush=True)
else: else:
# prompt for user input # prompt for user input
client_message = input() client_message = input()

View file

@ -1,3 +1,4 @@
import os
import socket import socket
import select import select
@ -5,6 +6,18 @@ CHATPORT = 8181
BUFFER_SIZE = 1024 BUFFER_SIZE = 1024
MAX_CONNECT_QUEUE = 10 MAX_CONNECT_QUEUE = 10
def format_file_info(file_path):
"""Helper function to format file information."""
file_size = os.path.getsize(file_path)
if file_size < 1000:
size_str = f"{file_size} B"
elif file_size < 1000000:
size_str = f"{file_size / 1000:.2f} KB"
else:
size_str = f"{file_size / 1000000:.2f} MB"
file_type = "Directory" if os.path.isdir(file_path) else "File"
return f"{os.path.basename(file_path)} - {file_type} - {size_str}"
def main(): def main():
# set the flag variable to true for infinite loop # set the flag variable to true for infinite loop
quitFlag = True quitFlag = True
@ -31,6 +44,8 @@ def main():
# keep track of the states of each client connected, and if they are # keep track of the states of each client connected, and if they are
# technically in an 'unsafe' state like in change username or chatroom mode. # technically in an 'unsafe' state like in change username or chatroom mode.
client_states = {} client_states = {}
# Add a dictionary to store user-specific paths
user_paths = {}
# let the user know the server is listening on port CHATPORT. # let the user know the server is listening on port CHATPORT.
print(f"Chatserver listening on port: {CHATPORT}") print(f"Chatserver listening on port: {CHATPORT}")
@ -50,6 +65,7 @@ def main():
client_socket.send(b"\nUse '%!' to exit, or '%?' for help.\n") client_socket.send(b"\nUse '%!' to exit, or '%?' for help.\n")
client_socket.send(b"\nType in a username: ") client_socket.send(b"\nType in a username: ")
client_states[client_socket] = "WAITING_FOR_USERNAME" client_states[client_socket] = "WAITING_FOR_USERNAME"
user_paths[client_socket] = None # Initialize path for new client
# otherwise the socket is a client socket. # otherwise the socket is a client socket.
else: else:
# try to receive the message from the client # try to receive the message from the client
@ -62,6 +78,7 @@ def main():
chat_rooms[sock] = "default" chat_rooms[sock] = "default"
sock.send(b"\nUsername accepted. You are now in the 'default' chatroom.") sock.send(b"\nUsername accepted. You are now in the 'default' chatroom.")
client_states[sock] = "NORMAL" client_states[sock] = "NORMAL"
user_paths[sock] = None # Initialize path for the user
elif state == "WAITING_FOR_NEW_USERNAME": elif state == "WAITING_FOR_NEW_USERNAME":
usernames[sock] = message.strip() usernames[sock] = message.strip()
sock.send(b"\nUsername changed successfully.") sock.send(b"\nUsername changed successfully.")
@ -75,8 +92,82 @@ def main():
if old_chatroom != "default" and old_chatroom not in chat_rooms.values(): if old_chatroom != "default" and old_chatroom not in chat_rooms.values():
print(f"\nChatroom '{old_chatroom}' is empty and removed.") print(f"\nChatroom '{old_chatroom}' is empty and removed.")
client_states[sock] = "NORMAL" client_states[sock] = "NORMAL"
else: elif state == "NORMAL":
if message.strip() == "%!": if message.startswith("@") and "-ls" in message:
# Parse the message format: @RECEIVING_USERNAME@SENDING_USERNAME -ls
parts = message.split()
if len(parts) >= 2 and "-ls" in parts[1]:
usernames_part = parts[0]
if usernames_part.count("@") == 2:
receiving_username, sending_username = usernames_part[1:].split("@")
# Find the receiving user's socket
receiving_sock = next(
(s for s, u in usernames.items() if u == receiving_username), None
)
sending_sock = next(
(s for s, u in usernames.items() if u == sending_username), None
)
if receiving_sock and sending_sock:
user_path = user_paths.get(receiving_sock)
if user_path and os.path.isdir(user_path):
# List files in the receiving user's directory
files = os.listdir(user_path)
if files:
file_list = "\n".join(
[format_file_info(os.path.join(user_path, f)) for f in files]
)
sending_sock.send(
f"Files in {receiving_username}'s directory:\n{file_list}".encode('utf-8')
)
else:
sending_sock.send(
f"No files in {receiving_username}'s directory.".encode('utf-8')
)
else:
sending_sock.send(
f"Error: {receiving_username} has no valid directory set.".encode('utf-8')
)
else:
sock.send(b"Error: One or both users not found.")
else:
sock.send(b"Error: Invalid message format.")
elif message.startswith("@") and "-f" in message:
# Parse the message format: @RECEIVING_USERNAME@SENDING_USERNAME -f FILENAME
parts = message.split()
if len(parts) >= 3 and "-f" in parts[1]:
usernames_part = parts[0]
if usernames_part.count("@") == 2:
receiving_username, sending_username = usernames_part[1:].split("@")
# Find the receiving user's socket
receiving_sock = next(
(s for s, u in usernames.items() if u == receiving_username), None
)
sending_sock = next(
(s for s, u in usernames.items() if u == sending_username), None
)
if receiving_sock and sending_sock:
if len(parts) == 3:
# File request: @RECEIVING_USERNAME@SENDING_USERNAME -f FILENAME
filename = parts[2]
receiving_sock.send(
f"FILE_REQUEST {sending_username} {filename}".encode('utf-8')
)
elif len(parts) > 5 and parts[-1] == "ENDFILE":
# File transfer: @RECEIVING_USERNAME@SENDING_USERNAME -f FILENAME FILETYPE FILELENGTH FILEBYTES ENDFILE
filename = parts[2]
filetype = parts[3]
filelength = int(parts[4])
filebytes = " ".join(parts[5:-1]).encode('utf-8')
receiving_sock.send(
f"FILE_TRANSFER {sending_username} {filename} {filetype} {filelength}".encode('utf-8')
)
receiving_sock.send(filebytes)
receiving_sock.send(b"ENDFILE")
else:
sock.send(b"Error: One or both users not found.")
else:
sock.send(b"Error: Invalid message format.")
elif message.strip() == "%!":
sock.close() sock.close()
socket_list.remove(sock) socket_list.remove(sock)
del usernames[sock] del usernames[sock]