Implementation of FTP File Transfer in Terminal Based on Python

Keywords: PHP socket Python ftp Programming

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()

Posted by wisedj on Mon, 07 Oct 2019 19:49:19 -0700