python实现一个简单的ftp程序

客户端可以向服务器端下载,上传文件

下载文件指令:get_filename

上传文件指令:put_filename

ftp工程目录:

ftp工作原理:

put指令工作原理图:

put指令工作原理图:

代码:

客户端:

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.dump(msg).encode()) #将文件的信息一次性传给服务器端,这个地方dump是将json文本类型转化为其他存储格式
                print('等待服务器端返回确认指令!')
                server_response = self.client.recv(1024) # 接收服务器端发送来的确认指令
                f = open(filename,'wb')
                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.dump(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('localhost',9999)
ftp.interaction()

服务器端:

import os,socketserver,json
class MyTCPHandler(socketserver.BaseRequestHandler):
    def put(self,*args):
        data_json = args[0] # 得到json文本
        filename = data_json['filename'] # 得到文件名
        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 # 得到这个文件的大小
            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("err", e)
                break

HOST, PORT = "localhost", 9999
server = socketserver.ThreadingTCPServer((HOST, PORT), MyTCPHandler)
server.serve_forever()

猜你喜欢

转载自blog.csdn.net/qq_40938077/article/details/84326746
今日推荐