Implementing FTP File Transfer in Terminal
Code structure:
.
├── client.py
├── readme.txt
└── server.py
Operating screenshots:
readme.txt
tftp file server Project function: * The client has a simple page command prompt * Functions include: 1. View the File List (Ordinary File) in the Server File Library - > os. listdir 2. You can download one of the files to your local location. 3. Client files can be uploaded to server file library * Server requirements: 1. Allow multiple clients to operate simultaneously 2. Each client may send commands continuously Technical analysis: 1. TCP socket is more suitable for file transfer 2. Concurrent scheme - > fork multi-process concurrency 3. Reading and Writing of Documents 4. Get a list of files - > os. listdir () or tree 5. Treatment of sticky package Integral structure design: 1. Server functions are encapsulated in classes (upload, download, view lists) 2. Create sockets and process function calls main() 3. The client is responsible for initiating requests, receiving replies and displaying them. 4. The server is responsible for accepting requests and processing them logically. Programming implementation: 1. Setting up the whole structure and creating the network connection 2. Creating multi-process and class structures 3. Implementation of each functional module Modular approach: os.listdir(path) os.path.isfile() os.path.isdir()
server.py
# server.py import struct from socket import * import os import signal import sys import time # File Library FILE_PATH = '/home/noon/Python/Example/' # Implementing Function Modules class TftpServer(object): def __init__(self, sockfd, addr): super().__init__() self.sockfd = sockfd self.addr = addr self.opt = '' def display(self): re = '' for i in os.listdir(FILE_PATH): re += i + '\n' self.sockfd.send(re.encode()) def download(self): 'Function Implementation of Download Module' # Try to open the file filename = FILE_PATH + self.opt.split(' ')[1] print(filename) try: fp = open(filename, 'rb') except: self.sockfd.send(b'Failed to open file') else: self.sockfd.send(b'Ready to transfer') # Cyclic sending of data while True: data = fp.read(1024) if not data: # If the transmission is complete, data For empty, transfer 0, jump out of the loop res = struct.pack('i', 0) self.sockfd.send(res) break res = struct.pack('i', len(data)) self.sockfd.send(res) self.sockfd.send(data) print('Done!') def upload(self): filename = FILE_PATH + self.opt.split(' ')[1] try: fp = open(filename, 'wb') except: self.sockfd.send('Unable to open file'.encode()) else: self.sockfd.send(b'Ready to upload') while True: res = self.sockfd.recv(4) length = struct.unpack('i', res)[0] if length == 0: break data = self.sockfd.recv(length) fp.write(data) fp.close() print('Done!') def quit(self): print(self.addr, 'Disconnect') self.sockfd.close() sys.exit() # Main stream def main(): HOST = '0.0.0.0' PORT = 5555 ADDR = (HOST, PORT) sockfd = socket() sockfd.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1) sockfd.bind(ADDR) sockfd.listen(5) # Notify the kernel that it is not concerned about the end of the child process,Recovered by the kernel. signal.signal(signal.SIGCHLD, signal.SIG_IGN) while True: try: connfd, addr = sockfd.accept() except KeyboardInterrupt: sockfd.close() sys.exit('Server exit') except Exception as e: print(e) continue print('Successful connection:', addr) # Create subprocesses pid = os.fork() if pid == 0: sockfd.close() tftp = TftpServer(connfd, addr) while True: tftp.opt = connfd.recv(1024).decode() if tftp.opt == 'display': tftp.display() elif tftp.opt.startswith('download'): tftp.download() elif tftp.opt.startswith('upload'): tftp.upload() elif tftp.opt == 'quit': tftp.quit() else: connfd.close() continue if __name__ == '__main__': main()
client.py
# client.py from socket import * import sys import time import struct # Implementing various functional requests class TftpClient(object): def __init__(self, sockfd): super().__init__() self.sockfd = sockfd self.opt = '' def panel(self): print('+', '*'*30, '+', sep='') print('+', 'display'.center(30), '+', sep='') print('+', 'download'.center(30), '+', sep='') print('+', 'upload'.center(30), '+', sep='') print('+', 'quit'.center(30), '+', sep='') print('+', '*'*30, '+', sep='') def display(self): self.sockfd.send(b'display') print(self.sockfd.recv(1024).decode()) def download(self): 'Client download request' # First use display The command requests a list of files from the server to verify the existence of the files the user wants to download. filename = input('filename>> ') if not filename: return self.sockfd.send(b'display') files = self.sockfd.recv(1024).decode().split('\n') if not filename in files: print('Cannot locate', filename) return # File exists, send download request to server and receive return result data = 'download ' + filename self.sockfd.send(data.encode()) data = self.sockfd.recv(1024).decode() # If the server cannot open the file if data == 'Failed to open file': print('Failed to open file') # You can perform download operations else: # Call write method print(data) self.write(filename) print('Done!') def write(self, filename): 'Download files from the server' # Considering the sticking problem, import struct Module, receiving the size of data to be sent by the server, and then according to this size to receive data, circular execution fp = open(filename, 'wb') while True: # Receive data size, call struct.unpack Method to get data size res = self.sockfd.recv(4) length = struct.unpack('i', res)[0] # If the data size is 0, the transfer ends and the loop exits. if length == 0: break # Receiving data by size data = self.sockfd.recv(length) fp.write(data) fp.close() def upload(self): # File path filepath = input('filepath>> ') try: fp = open(filepath, 'rb') except: print('Unable to open', filepath) return else: # File upload to save why name # First use display The command requests a list of files from the server to verify that the file name that the user wants to upload exists filename = input('filename>> ') if not filename: return self.sockfd.send(b'display') files = self.sockfd.recv(1024).decode().split('\n') if filename in files: print('File already exists!') return # Can upload data = 'upload ' + filename self.sockfd.send(data.encode()) data = self.sockfd.recv(1024).decode() if data == 'Unable to open file': print('Server Open File Error') return else: self.read(fp) def read(self, fp): 'Read File Upload Server' while True: data = fp.read(1024) if not data: res = struct.pack('i', 0) self.sockfd.send(res) break res = struct.pack('i', len(data)) self.sockfd.send(res) self.sockfd.send(data) print('Done!') def quit(self): self.sockfd.send(b'quit') self.sockfd.close() sys.exit('Client shutdown') # Create sockets, establish connections def main(): argc = len(sys.argv) if argc != 3: sys.exit('Usage: python client.py host port') else: HOST = sys.argv[1] PORT = int(sys.argv[2]) ADDR = HOST, PORT sockfd = socket() try: sockfd.connect(ADDR) except ConnectionRefusedError: sys.exit('Unable to connect to server') tftp = TftpClient(sockfd) tftp.panel() while True: try: tftp.opt = input('>> ').lower() except KeyboardInterrupt: tftp.quit() if tftp.opt == 'display': tftp.display() elif tftp.opt == 'download': tftp.download() elif tftp.opt == 'upload': tftp.upload() elif tftp.opt == 'quit': tftp.quit() else: continue if __name__ == '__main__': main()