编写ftp客户端程序:

import socket, os, json


class my_ftp_client(object):
    def __init__(self):
        self.client = socket.socket()

    def help(self):
        msg = '''
        get filename
        put filename
        '''

    def connect(self, ip, port):  # 与服务器端建立连接,ip代表服务器端的ip地址,port代表服务器端的端口
        self.client.connect((ip, port))

    def interaction(self):  # 让用户输入执行,然后调用对应的函数来与服务器端进行交互
        while True:
            data = input("<<").strip()  # 用户输入指令
            if len(data) == 0:  # 如果指令输入有误,重新输入
                continue
            data_one = data.split()[0]  # 得到用户输入的操作,如果用户如果输入'put filename'(往服务器端传文件名为filename的文件),那么data_one就是'put'
            if hasattr(self, "cmd_%s" % data_one):  # 如果我们写的这个类中有名为'cmd_put'的函数,就执行下面的代码
                func = getattr(self, "cmd_%s" % data_one)  # func实际上就是'cmd_put'
                func(data)  # 调用类中名为'cmd_put'的函数
            else:
                self.help()

    def cmd_put(self, *args):
        data_split = args[0].split()  # 得到用户输入的指令
        if len(data_split) > 1:  # 确保指令是正确的
            filename = data_split[1]  # 得到文件名
            if os.path.isfile(filename):  # 这是个文件
                filesize = os.stat(filename).st_size
                msg = {  # 定义一个json文本,里面存储的是文件的一些信息
                    'action': 'put',  # 文件对客户端的操作
                    'filename': filename,  # 文件名
                    'filesize': filesize,  # 文件大小
                }
                self.client.send(json.dumps(msg).encode())  # 将文件的信息一次性传给服务器端,这个地方dump是将json文本类型转化为其他存储格式
                print('等待服务器端返回确认指令!')
                server_response = self.client.recv(1024)  # 接收服务器端发送来的确认指令
                f = open(filename, 'rb')
                for line in f:  # 遍历文件,将文件内容传送给服务器端
                    self.client.send(line)
                else:
                    print("file end!")
        else:  # 指令是错误的
            print("instruction error!")

    def cmd_get(self, *args):  # 这个函数是从客户端得到名为filename的文件
        data_split = args[0].split()  # 得到用户输入的指令
        if len(data_split) > 1:  # 指令正确,执行下面的操作
            file_name = data_split[1]  # 得到文件名
            msg = {  # 定义一个json文本,里面存储的是文件的一些信息
                'action': 'get',  # 文件对客户端的操作
                'filename': file_name,  # 文件名
            }
            self.client.send(json.dumps(msg).encode())  # 给服务器端发送这个文件的信息
            print('等待服务器端返回确认指令!')
            recevice_data = self.client.recv(1024).strip()  # 接收服务器端发送回来的指令
            data_json = json.loads(recevice_data.decode())  # 将recevice_data解析出来
            One_data = data_json["instruction"]  # 得到服务器端发回来的第一个信息
            if One_data == 'Not Find':  # 如果第一个信息为'Not Find',说明服务器端没有名为file_name的文件
                return
            else:  # 否则,有名为file_name的文件
                file_size = data_json["file_size"]  # 得到这个文件的大小
                now_size = 0  # 当前接收到的文件的大小
                f = open(file_name, 'wb')
                while now_size < file_size:  # 开始接收文件
                    data = self.client.recv(1024)
                    f.write(data)
                    now_size += len(data)
                else:
                    print("文件接收完毕!")


ftp = my_ftp_client()
ftp.connect('127.0.0.1', 8000)
ftp.interaction()

编写ftp服务端程序:

import os
import socketserver
import json


class MyTCPHandler(socketserver.BaseRequestHandler):
    def put(self, *args):
        data_json = args[0]  # 得到json文本
        fullname = data_json['filename']  # 得到文件名
        """
        提供上传文件和文件夹的功能:
        (1)上传文件,接受的信息为:111.txt
        (2)上传文件夹,接受的信息为(文件夹名为:111):111
        """
        file_path = os.path.join(os.getcwd(), os.path.split(os.path.split(fullname)[0])[-1])
        if not os.path.exists(file_path):
            os.makedirs(file_path)
        filename = os.path.join(file_path, os.path.split(fullname)[-1])

        filesize = data_json['filesize']  # 得到文件的大小
        now_size = 0  # 这是服务器端已经接收到的文件的大小
        if os.path.isfile(filename):  # 如果服务器端已经存在名为filename的文件,就新建一个名为'filename.new'的文件
            f = open(filename + '.new', 'wb')
        else:  # 否则,就建出名为filename的文件
            f = open(filename, 'wb')
        self.request.send(b'200 ojbk')  # 给客户端返回服务器端已经准备好接受文件的信息
        while now_size < filesize:  # 开始接收文件
            data = self.request.recv(1024)
            f.write(data)  # 将接收到的文件的内容写入到服务器端中的名为filename的文件中去
            now_size += len(data)  # now_size加
        else:
            print("file recv over!")  # 文件接收完毕

    def get(self, *args):
        data_json = args[0]  # 得到客户端发送来的信息
        file_name = data_json['filename']  # 得到客户端想要从服务器端获取的文件的文件名
        if os.path.isfile(file_name):  # 服务器端有这个文件
            filesize = os.stat(file_name).st_size  # 得到这个文件的大小
            xiao_name = os.path.split(file_name)[-1]
            msg = {  # 将这个文件的信息传给服务器端
                "instruction": 'Find the file',  # 这个信息说明服务器端已经找到了这个文件了
                "file_size": filesize,  # 返回给客户端这个文件的大小
            }
            self.request.send(json.dumps(msg).encode())
            f = open(file_name, 'rb')  # 打开这个文件
            for line in f:  # 给客户端发送文件内容
                self.request.send(line)
            else:
                print("文件传输完毕!")
        else:  # 服务器端没有这个文件
            msg = {
                "instruction": 'Not Find',  # 这个信息说明服务器端没有找到这个文件
                'file_size': 0  # 文件大小为0
            }
            self.request.send(json.dumps(msg).encode())

    def handle(self):
        while True:
            try:
                self.data = self.request.recv(1024).strip()
                print("{} wrote".format(self.client_address[0]))  # 打印客户端的ip地址
                print("data:", self.data)
                data_json = json.loads(self.data.decode())
                action = data_json['action']  # 得到要执行的操作
                if hasattr(self, action):  # 这个类中有名为action的函数
                    func = getattr(self, action)  # func就相当于是'action'
                    func(data_json)
            except ConnectionResetError as e:  # 捕捉到错误了
                print("error:", e)
                break


HOST, PORT = "127.0.0.1", 8000  # 填写服务器的ip,端口
server = socketserver.ThreadingTCPServer((HOST, PORT), MyTCPHandler)  # 实例化ThreadingTCPServer,并传递(端口号+IP),和请求类名
server.serve_forever()  # 关闭

 
分别运行客户端和服务端的程序,在客户端输入:put 文件夹名/文件名可以将文件上传到服务端,在客户端输入:get 文件名可以将文件从服务端下载到客户端,以上就是ftp实现文件上传和下载的基本方法,各位读者有疑问的可以私信博主或评论留下足迹。