Question





Goals: 1. To understand the challenges of protocol design. 2. To discover and appreciate the challenges of developing complex
0 0
Add a comment Improve this question Transcribed image text
Answer #1

The given implementation is in python.

1) The server code - server.py

###################################################################

import socket
import sys
import time
import os
import struct

print "\nWelcome to the FTP server.\n\nTo get started, connect a client."

# Initialise socket stuff
TCP_IP = "127.0.0.1" # Only a local server
TCP_PORT = 1456 # Just a random choice
BUFFER_SIZE = 1024 # Standard size
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind((TCP_IP, TCP_PORT))
s.listen(1)
conn, addr = s.accept()

print "\nConnected to by address: {}".format(addr)

def upld():
# Send message once server is ready to recieve file details
conn.send("1")
# Recieve file name length, then file name
file_name_size = struct.unpack("h", conn.recv(2))[0]
file_name = conn.recv(file_name_size)
# Send message to let client know server is ready for document content
conn.send("1")
# Recieve file size
file_size = struct.unpack("i", conn.recv(4))[0]
# Initialise and enter loop to recive file content
start_time = time.time()
output_file = open(file_name, "wb")
# This keeps track of how many bytes we have recieved, so we know when to stop the loop
bytes_recieved = 0
print "\nRecieving..."
while bytes_recieved < file_size:
l = conn.recv(BUFFER_SIZE)
output_file.write(l)
bytes_recieved += BUFFER_SIZE
output_file.close()
print "\nRecieved file: {}".format(file_name)
# Send upload performance details
conn.send(struct.pack("f", time.time() - start_time))
conn.send(struct.pack("i", file_size))
return

def list_files():
print "Listing files..."
# Get list of files in directory
listing = os.listdir(os.getcwd())
# Send over the number of files, so the client knows what to expect (and avoid some errors)
conn.send(struct.pack("i", len(listing)))
total_directory_size = 0
# Send over the file names and sizes whilst totaling the directory size
for i in listing:
# File name size
conn.send(struct.pack("i", sys.getsizeof(i)))
# File name
conn.send(i)
# File content size
conn.send(struct.pack("i", os.path.getsize(i)))
total_directory_size += os.path.getsize(i)
# Make sure that the client and server are syncronised
conn.recv(BUFFER_SIZE)
# Sum of file sizes in directory
conn.send(struct.pack("i", total_directory_size))
#Final check
conn.recv(BUFFER_SIZE)
print "Successfully sent file listing"
return

def dwld():
conn.send("1")
file_name_length = struct.unpack("h", conn.recv(2))[0]
print file_name_length
file_name = conn.recv(file_name_length)
print file_name
if os.path.isfile(file_name):
# Then the file exists, and send file size
conn.send(struct.pack("i", os.path.getsize(file_name)))
else:
# Then the file doesn't exist, and send error code
print "File name not valid"
conn.send(struct.pack("i", -1))
return
# Wait for ok to send file
conn.recv(BUFFER_SIZE)
# Enter loop to send file
start_time = time.time()
print "Sending file..."
content = open(file_name, "rb")
# Again, break into chunks defined by BUFFER_SIZE
l = content.read(BUFFER_SIZE)
while l:
conn.send(l)
l = content.read(BUFFER_SIZE)
content.close()
# Get client go-ahead, then send download details
conn.recv(BUFFER_SIZE)
conn.send(struct.pack("f", time.time() - start_time))
return


def delf():
# Send go-ahead
conn.send("1")
# Get file details
file_name_length = struct.unpack("h", conn.recv(2))[0]
file_name = conn.recv(file_name_length)
# Check file exists
if os.path.isfile(file_name):
conn.send(struct.pack("i", 1))
else:
# Then the file doesn't exist
conn.send(struct.pack("i", -1))
# Wait for deletion conformation
confirm_delete = conn.recv(BUFFER_SIZE)
if confirm_delete == "Y":
try:
# Delete file
os.remove(file_name)
conn.send(struct.pack("i", 1))
except:
# Unable to delete file
print "Failed to delete {}".format(file_name)
conn.send(struct.pack("i", -1))
else:
# User abandoned deletion
# The server probably recieved "N", but else used as a safety catch-all
print "Delete abandoned by client!"
return


def quit():
# Send quit conformation
conn.send("1")
# Close and restart the server
conn.close()
s.close()
os.execl(sys.executable, sys.executable, *sys.argv)

while True:
# Enter into a while loop to recieve commands from client
print "\n\nWaiting for instruction"
data = conn.recv(BUFFER_SIZE)
print "\nRecieved instruction: {}".format(data)
# Check the command and respond correctly
if data == "UPLD":
upld()
elif data == "LIST":
list_files()
elif data == "DWLD":
dwld()
elif data == "DELF":
delf()
elif data == "QUIT":
quit()
# Reset the data to loop
data = None

###################################################################

2) The client code - client.py

import socket
import sys
import os
import struct

# Initialise socket stuff
TCP_IP = "127.0.0.1" # Only a local server
TCP_PORT = 1456 # Just a random choice
BUFFER_SIZE = 1024 # Standard chioce
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

def conn():
# Connect to the server
print "Sending server request..."
try:
s.connect((TCP_IP, TCP_PORT))
print "Connection sucessful"
except:
print "Connection unsucessful. Make sure the server is online."

def upld(file_name):
# Upload a file
print "\nUploading file: {}...".format(file_name)
try:
# Check the file exists
content = open(file_name, "rb")
except:
print "Couldn't open file. Make sure the file name was entered correctly."
return
try:
# Make upload request
s.send("UPLD")
except:
print "Couldn't make server request. Make sure a connection has bene established."
return
try:
# Wait for server acknowledgement then send file details
# Wait for server ok
s.recv(BUFFER_SIZE)
# Send file name size and file name
s.send(struct.pack("h", sys.getsizeof(file_name)))
s.send(file_name)
# Wait for server ok then send file size
s.recv(BUFFER_SIZE)
s.send(struct.pack("i", os.path.getsize(file_name)))
except:
print "Error sending file details"
try:
# Send the file in chunks defined by BUFFER_SIZE
# Doing it this way allows for unlimited potential file sizes to be sent
l = content.read(BUFFER_SIZE)
print "\nSending..."
while l:
s.send(l)
l = content.read(BUFFER_SIZE)
content.close()
# Get upload performance details
upload_time = struct.unpack("f", s.recv(4))[0]
upload_size = struct.unpack("i", s.recv(4))[0]
print "\nSent file: {}\nTime elapsed: {}s\nFile size: {}b".format(file_name, upload_time, upload_size)
except:
print "Error sending file"
return
return

def list_files():
# List the files avaliable on the file server
# Called list_files(), not list() (as in the format of the others) to avoid the standard python function list()
print "Requesting files...\n"
try:
# Send list request
s.send("LIST")
except:
print "Couldn't make server request. Make sure a connection has bene established."
return
try:
# First get the number of files in the directory
number_of_files = struct.unpack("i", s.recv(4))[0]
# Then enter into a loop to recieve details of each, one by one
for i in range(int(number_of_files)):
# Get the file name size first to slightly lessen amount transferred over socket
file_name_size = struct.unpack("i", s.recv(4))[0]
file_name = s.recv(file_name_size)
# Also get the file size for each item in the server
file_size = struct.unpack("i", s.recv(4))[0]
print "\t{} - {}b".format(file_name, file_size)
# Make sure that the client and server are syncronised
s.send("1")
# Get total size of directory
total_directory_size = struct.unpack("i", s.recv(4))[0]
print "Total directory size: {}b".format(total_directory_size)
except:
print "Couldn't retrieve listing"
return
try:
# Final check
s.send("1")
return
except:
print "Couldn't get final server confirmation"
return


def dwld(file_name):
# Download given file
print "Downloading file: {}".format(file_name)
try:
# Send server request
s.send("DWLD")
except:
print "Couldn't make server request. Make sure a connection has bene established."
return
try:
# Wait for server ok, then make sure file exists
s.recv(BUFFER_SIZE)
# Send file name length, then name
s.send(struct.pack("h", sys.getsizeof(file_name)))
s.send(file_name)
# Get file size (if exists)
file_size = struct.unpack("i", s.recv(4))[0]
if file_size == -1:
# If file size is -1, the file does not exist
print "File does not exist. Make sure the name was entered correctly"
return
except:
print "Error checking file"
try:
# Send ok to recieve file content
s.send("1")
# Enter loop to recieve file
output_file = open(file_name, "wb")
bytes_recieved = 0
print "\nDownloading..."
while bytes_recieved < file_size:
# Again, file broken into chunks defined by the BUFFER_SIZE variable
l = s.recv(BUFFER_SIZE)
output_file.write(l)
bytes_recieved += BUFFER_SIZE
output_file.close()
print "Successfully downloaded {}".format(file_name)
# Tell the server that the client is ready to recieve the download performance details
s.send("1")
# Get performance details
time_elapsed = struct.unpack("f", s.recv(4))[0]
print "Time elapsed: {}s\nFile size: {}b".format(time_elapsed, file_size)
except:
print "Error downloading file"
return
return


def delf(file_name):
# Delete specified file from file server
print "Deleting file: {}...".format(file_name)
try:
# Send resquest, then wait for go-ahead
s.send("DELF")
s.recv(BUFFER_SIZE)
except:
print "Couldn't connect to server. Make sure a connection has been established."
return
try:
# Send file name length, then file name
s.send(struct.pack("h", sys.getsizeof(file_name)))
s.send(file_name)
except:
print "Couldn't send file details"
return
try:
# Get conformation that file does/doesn't exist
file_exists = struct.unpack("i", s.recv(4))[0]
if file_exists == -1:
print "The file does not exist on server"
return
except:
print "Couldn't determine file existance"
return
try:
# Confirm user wants to delete file
confirm_delete = raw_input("Are you sure you want to delete {}? (Y/N)\n".format(file_name)).upper()
# Make sure input is valid
# Unfortunately python doesn't have a do while style loop, as that would have been better here
while confirm_delete != "Y" and confirm_delete != "N" and confirm_delete != "YES" and confirm_delete != "NO":
# If user input is invalid
print "Command not recognised, try again"
confirm_delete = raw_input("Are you sure you want to delete {}? (Y/N)\n".format(file_name)).upper()
except:
print "Couldn't confirm deletion status"
return
try:
# Send conformation
if confirm_delete == "Y" or confirm_delete == "YES":
# User wants to delete file
s.send("Y")
# Wait for conformation file has been deleted
delete_status = struct.unpack("i", s.recv(4))[0]
if delete_status == 1:
print "File successfully deleted"
return
else:
# Client will probably send -1 to get here, but an else is used as more of a catch-all
print "File failed to delete"
return
else:
s.send("N")
print "Delete abandoned by user!"
return
except:
print "Couldn't delete file"
return

def quit():
s.send("QUIT")
# Wait for server go-ahead
s.recv(BUFFER_SIZE)
s.close()
print "Server connection ended"
return

print "\n\nWelcome to the FTP client.\n\nCall one of the following functions:\nCONN : Connect to server\nUPLD file_path : Upload file\nLIST : List files\nDWLD file_path : Download file\nDELF file_path : Delete file\nQUIT : Exit"

while True:
# Listen for a command
prompt = raw_input("\nEnter a command: ")
if prompt[:4].upper() == "CONN":
conn()
elif prompt[:4].upper() == "UPLD":
upld(prompt[5:])
elif prompt[:4].upper() == "LIST":
list_files()
elif prompt[:4].upper() == "DWLD":
dwld(prompt[5:])
elif prompt[:4].upper() == "DELF":
delf(prompt[5:])
elif prompt[:4].upper() == "QUIT":
quit()
break
else:
print "Command not recognised; please try again"

###################################################################

3) Usage

To run the server/client, call the appropriate program from the terminal. Each program will display a short message on startup:

> python server.py

Welcome to the FTP server.

To get started, connect a client.
> python client.py

Welcome to the FTP client.

Call one of the following functions:
CONN           : Connect to server
UPLD file_path : Upload file
LIST           : List files
DWLD file_path : Download file
DELF file_path : Delete file
QUIT           : Exit

Enter a command:

As indicated, the first thing that needs to be done is to connect the client to the server. To do this, just enter the command CONN:

Enter a command: CONN

The client will then attempt a connection. If successful a message will appear:

Enter a command: Connect

Sending a server request...
Connection successful

After that, all other commands can be entered through the client. Messages will display the progress of the request on both the client and server end. For example, to upload a file 'my_file.mp4', use the following command:

Enter a command: UPLD my_file.mp4

All standard file paths also work:

Enter a command: UPLD C:\Users\...\folder\my_file.mp4

When the server receives a file, it puts it in the same folder that it is in. Likewise, when the LIST command is used the server searches for files in the same folder that it is located in.

Add a comment
Know the answer?
Add Answer to:
Goals: 1. To understand the challenges of protocol design. 2. To discover and appreciate the challenges...
Your Answer:

Post as a guest

Your Name:

What's your source?

Earn Coins

Coins can be redeemed for fabulous gifts.

Not the answer you're looking for? Ask your own homework help question. Our experts will answer your question WITHIN MINUTES for Free.
Similar Homework Help Questions
  • Risk management in Information Security today Everyday information security professionals are bombarded with marketing messages around...

    Risk management in Information Security today Everyday information security professionals are bombarded with marketing messages around risk and threat management, fostering an environment in which objectives seem clear: manage risk, manage threat, stop attacks, identify attackers. These objectives aren't wrong, but they are fundamentally misleading.In this session we'll examine the state of the information security industry in order to understand how the current climate fails to address the true needs of the business. We'll use those lessons as a foundation...

  • How can we assess whether a project is a success or a failure? This case presents...

    How can we assess whether a project is a success or a failure? This case presents two phases of a large business transformation project involving the implementation of an ERP system with the aim of creating an integrated company. The case illustrates some of the challenges associated with integration. It also presents the obstacles facing companies that undertake projects involving large information technology projects. Bombardier and Its Environment Joseph-Armand Bombardier was 15 years old when he built his first snowmobile...

ADVERTISEMENT
Free Homework Help App
Download From Google Play
Scan Your Homework
to Get Instant Free Answers
Need Online Homework Help?
Ask a Question
Get Answers For Free
Most questions answered within 3 hours.
ADVERTISEMENT
ADVERTISEMENT
ADVERTISEMENT