zoukankan      html  css  js  c++  java
  • Python 程序:ftp

    Python 程序:ftp


    1、ftp实现功能

    2、目录结构

    3、代码

    4、效果展示


    一、ftp实现功能

    1、用户登陆认证

    2、多用户同时登陆

    3、不同用户家目录不同

    4、查看目录下文件

    5、用户可以在家目录下切换目录

    6、用户可以在家目录下创建目录

    7、用户可以在家目录下删除文件或目录

    8、用户磁盘配额(不同用户配额可不同,当文件大小超出服务器分配空间大小拒绝上传)

    9、上传:支持断点续传

    10、下载:支持断点续传和进度条显示

    二、目录结构

    三、代码

      1 import socket,os,json,sys
      2 class FtpClient(object):
      3 
      4     def __init__(self,ip,port):
      5         self.client = socket.socket()
      6         self.client.connect((ip,port))
      7         self.exit_flag = False
      8         self.interactive()
      9 
     10     def auth(self):
     11         retry_count = 0
     12         while retry_count < 3:
     13             username = input("username:").strip()
     14             if len(username) == 0:continue
     15             # passwd = getpass.getpass("password:")  #pycharm显示有问题
     16             passwd = input("passwd:").strip()
     17             msg_dic = {
     18                 "action":"ftp_auth",
     19                 "username":username,
     20                 "passwd":passwd
     21             }
     22             self.client.send(json.dumps(msg_dic).encode("utf-8"))
     23 
     24             auth_feedback = self.client.recv(1024)
     25             auth_feedback = auth_feedback.decode()
     26             if auth_feedback == "success":
     27                 print("33[32;1m登录成功!33[0m")
     28                 self.username  = username
     29                 self.cur_path = username
     30                 return True
     31             else:
     32                 print ("33[31;1m账号密码错误!33[0m")
     33                 retry_count +=1
     34         else:
     35             print ("33[31;1m尝试次数过多,exit!33[0m")
     36 
     37     def interactive(self):
     38         ftp_version = self.client.recv(1024)
     39         print(ftp_version.decode())
     40         self.auth()  #登录验证
     41         self.help()
     42         while True:
     43             cmd = input(">>:").strip()
     44             if len(cmd) == 0:
     45                 continue
     46             cmd_str = cmd.split()[0] #输入的第一个字符永远为指令,取出
     47             if hasattr(self,"cmd_%s"%cmd_str):
     48                 func = getattr(self,"cmd_%s"%cmd_str)
     49                 func(cmd)
     50             else:
     51                 self.help()
     52 
     53     def cmd_dir(self,*args):
     54         cmd_split = args[0].split()
     55         filename = ' '.join(cmd_split[1:])
     56         msg_dic = {
     57                     "action":cmd_split[0],
     58                     "filename":filename
     59                 }
     60         self.client.send(json.dumps(msg_dic).encode("utf-8"))
     61         # 防止粘包等服务器确认
     62         cmd_res_size = self.client.recv(1024)
     63         self.client.send(b"ok")
     64         cmd_res_size = int(cmd_res_size.decode())
     65         received_size = 0
     66         while received_size < cmd_res_size:
     67             data = self.client.recv(1024)
     68             received_size +=len(data)
     69             print(data.decode())
     70 
     71     def cmd_cd(self,*args):
     72 
     73         cmd_split = args[0].split()
     74         filename = ' '.join(cmd_split[1:])
     75         msg_dic = {
     76                     "action":cmd_split[0],
     77                     "filename":filename
     78                 }
     79         self.client.send(json.dumps(msg_dic).encode("utf-8"))
     80         feedback = self.client.recv(100)
     81         feedback = feedback.decode()
     82         if feedback.startswith("switch_dir::ok"):
     83             self.cur_path  = feedback.split("::")[-1]
     84         else:
     85             print ("33[31;1m%s33[0m" % feedback.split("::")[-1])
     86 
     87     def cmd_rmdir(self,*args):
     88         cmd_split = args[0].split()
     89         filename = ' '.join(cmd_split[1:])
     90         msg_dic = {
     91                     "action":cmd_split[0],
     92                     "filename":filename
     93                 }
     94         self.client.send(json.dumps(msg_dic).encode("utf-8"))
     95         feedback = self.client.recv(100)
     96         print(feedback.decode())
     97 
     98     def cmd_mkdir(self,*args):  #只支持创建目录,创建文件自己上传就行
     99         cmd_split = args[0].split()
    100         filename = ' '.join(cmd_split[1:])
    101         msg_dic = {
    102                     "action":cmd_split[0],
    103                     "filename":filename
    104                 }
    105         self.client.send(json.dumps(msg_dic).encode("utf-8"))
    106         feedback = self.client.recv(100)
    107         print(feedback.decode())
    108 
    109     def cmd_put(self,*args):
    110         cmd_split = args[0].split()
    111         if len(cmd_split) > 1:
    112             filename = cmd_split[1]
    113             if os.path.isfile(filename):
    114                 filesize = os.stat(filename).st_size
    115                 # msg_str = "%s|%s"%(filename,filesize)
    116                 msg_dic = {
    117                     "action":cmd_split[0],
    118                     "filename":filename,
    119                     "size":filesize,
    120                     "has_file":False
    121                 }
    122                 self.client.send(json.dumps(msg_dic).encode("utf-8"))
    123                 #防止粘包等服务器确认
    124                 server_response = self.client.recv(1024)  #此时服务器端判断大小是否超出磁盘配额,返回参数
    125                 data = server_response.decode()
    126                 data_list= data.split("|")
    127                 if data_list[0] == "ok" and data_list[1] == "no":
    128                     f = open(filename,"rb")
    129                     for line in f :
    130                         self.client.send(line)
    131                     else:
    132                         print("file upload success..")
    133                     f.close()
    134                 elif data_list[0] == "ok" and data_list[1] != "no":
    135                     print(data_list[1])
    136                     size = int(data_list[1])
    137                     f = open(filename,"rb")
    138                     f.seek(size)#seek到断点位置
    139                     for line in f :
    140                         self.client.send(line)
    141                     else:
    142                         print("file upload success..")
    143                     f.close()
    144                 else:
    145                     print(server_response.decode())
    146             else:
    147                 print(filename,"is not exist")
    148 
    149     def cmd_get(self,*args):
    150         cmd_split = args[0].split()
    151         if len(cmd_split) > 1:
    152             filename = cmd_split[1]
    153             msg_dic = {
    154                 "action":cmd_split[0],
    155                 "filename":filename,
    156                 "size":0,
    157                 "overridden":True
    158             }
    159 
    160             if os.path.isfile(filename):
    161                 print("文件已存在")
    162                 old_size = os.stat(filename).st_size
    163                 msg_dic["size"] = old_size
    164             else:
    165                 print("文件不存在")
    166                 old_size = 0
    167                 msg_dic["size"] = old_size
    168 
    169             self.client.send(json.dumps(msg_dic).encode("utf-8"))
    170             #防止粘包等服务器确认
    171             data = self.client.recv(1024)
    172             server_response = json.loads(data.decode())
    173 
    174             if server_response["filename"] is not None:
    175                 file_name = server_response["filename"]
    176                 if old_size>=server_response["size"]:
    177                     print("文件已下载完毕!")        #文件已下载完毕
    178                     received_size = old_size
    179                 else:
    180                     f = open(filename, 'ab')
    181                     received_size = old_size
    182                 self.client.send(b"ok")
    183                 while received_size < server_response["size"]:
    184                     if server_response["size"] - received_size >= 1024: #此时要收不只一次
    185                         size = 1024
    186                     else:   #最后一次收的数据大小,防止多收,避免粘包
    187                         size = server_response["size"] - received_size
    188                     data = self.client.recv(1024)
    189                     received_size += len(data)  #每次收到的大小
    190                     f.write(data)
    191                     cur_percent = received_size / server_response["size"] * 100
    192                     self.show_progress(server_response["size"],received_size,cur_percent)   #显示进度条
    193                 print("下载成功!")
    194             else:
    195                 print("文件不存在!")
    196 
    197     def show_progress(self,total,finished,percent):
    198         progress_mark = "=" * int(percent/2)
    199         sys.stdout.write("[%s/%s]%s>%s
    " %(total,finished,progress_mark,percent))
    200         sys.stdout.flush()
    201         if percent == 100:
    202             print ('
    ')
    203 
    204     def help(self):
    205         msg = '''
    206      ---命令菜单---
    207         dir
    208         mkdir filename
    209         rmdir filename
    210         cd filename
    211         get filename
    212         put filename
    213         '''
    214         print(msg)
    215 
    216 ftp = FtpClient("localhost",9999)
    ftp_client
      1 import socketserver,json,os
      2 import user_data
      3 from os.path import join, getsize
      4 
      5 class MyTCPHandler(socketserver.BaseRequestHandler):
      6     def ftp_auth(self,*args):
      7         print ('----auth----')
      8         auth_res = False
      9         cmd_dic = args[0]
     10         if len(cmd_dic) == 3:
     11             msg_type = cmd_dic["action"]
     12             username = cmd_dic["username"]
     13             passwd = cmd_dic["passwd"]
     14             if username in user_data.accounts:
     15                 if user_data.accounts[username]['passwd'] == passwd:
     16                     auth_res = True
     17                     self.login_user = username
     18                     self.cur_path = '%s/%s' %(os.path.dirname(__file__),user_data.accounts[username]['home'])
     19                     self.home_path = '%s/%s' %(os.path.dirname(__file__),user_data.accounts[username]['home'])
     20                     self.quotation = user_data.accounts[username]['quotation']
     21                 else:
     22                     print ('---wrong passwd---')
     23                     auth_res = False
     24             else:
     25                 auth_res = False
     26         else:
     27             auth_res = False
     28         if auth_res:
     29             msg = "success"
     30             print ('33[32;1muser:%s has passed authentication!33[0m' %username)
     31         else:
     32             msg = "fail"
     33         self.request.send(msg.encode())
     34 
     35     def disk_size(self,dir):
     36         home_size = 0
     37         for root, dirs, files in os.walk(dir):
     38             home_size += sum([getsize(join(root, name)) for name in files])
     39         size = self.quotation - home_size
     40         return size
     41 
     42     def put(self,*args):
     43         '''接受客户端文件'''
     44         cmd_dic = args[0]
     45         filename = cmd_dic["filename"]
     46         filesize = cmd_dic["size"]
     47         size = self.disk_size(self.home_path)
     48         print(size,filesize)
     49         if size > int(filesize):
     50             if os.path.isfile(filename):
     51                 print("文件已存在")
     52                 old_size = os.stat(filename).st_size
     53                 print(old_size,filesize)
     54                 if old_size>=filesize:
     55                     self.request.send(b"ok|no")
     56                     f = open(filename + "_new","wb")        #文件已上传完毕,上传新的文件
     57                     received_size = 0
     58                 else:
     59                     b = "ok|%s"%old_size
     60                     self.request.send(b.encode())
     61                     f = open(filename, 'ab')
     62                     received_size = old_size
     63             else:
     64                 self.request.send(b"ok|no")
     65                 f = open(filename,"wb")
     66                 received_size = 0
     67 
     68             while received_size < filesize:
     69                 data = self.request.recv(1024)
     70                 f.write(data)
     71                 received_size += len(data)
     72             else:
     73                 print("file [%s] has uploaded.."%filename)
     74 
     75 
     76 
     77 
     78         else:
     79             result = "磁盘空间不足!"
     80             print(result)
     81             self.request.send(result.encode())
     82 
     83     def get(self,*args):
     84         '''客户端下载文件'''
     85         cmd_dic = args[0]
     86         filename = cmd_dic["filename"]
     87         get_size = cmd_dic["size"]
     88 
     89         if os.path.isfile(filename):  #判断是否已经存在
     90             filesize = os.stat(filename).st_size
     91             cmd_dic["size"] = filesize
     92             self.request.send(json.dumps(cmd_dic).encode("utf-8"))
     93             self.request.recv(1024)
     94             f = open(filename,"rb")
     95             f.seek(get_size)#seek到断点位置
     96             for line in f:
     97                 self.request.send(line)
     98             f.close()
     99 
    100         else:
    101             cmd_dic['filename'] = None
    102             self.request.send(json.dumps(cmd_dic).encode("utf-8"))
    103 
    104     def dir(self,*args):
    105         cmd_dic = args[0]
    106         action = cmd_dic["action"]
    107         filename = cmd_dic["filename"]
    108         home_prefix = user_data.accounts[self.login_user]['home']
    109         dir_path =  '%s/%s' %(self.cur_path,filename)
    110         os.chdir(dir_path)
    111         cmd_res = os.popen("dir").read()
    112         print(cmd_res)
    113         print(len(cmd_res.encode()))
    114         # if len(cmd_res.encode()) == 0 :
    115         #     cmd_res = "没有输出。。"
    116         self.request.send(str(len(cmd_res.encode())).encode())
    117         self.request.recv(1024)  #等客户端确认
    118         self.request.send(cmd_res.encode())
    119 
    120     def cd(self,*args):
    121         cmd_dic = args[0]
    122         action = cmd_dic["action"]
    123         filename = cmd_dic["filename"]
    124         if len(filename) == 0:# means no dir follows cd cmd, go back to home directory
    125             self.cur_path = self.home_path
    126             relative_path = self.cur_path.split(self.home_path)[-1]
    127             switch_res = "switch_dir::ok::%s" % relative_path
    128         else:
    129             if os.path.isdir("%s/%s" %(self.cur_path,filename)):
    130                 abs_path = "%s/%s" %(self.cur_path,filename)
    131                 if abs_path.startswith(self.home_path):
    132                     self.cur_path = abs_path
    133                     print("success")
    134                     relative_path = self.cur_path.split(self.home_path)[-1]
    135                     switch_res = "switch_dir::ok::%s" % relative_path
    136                 else:
    137                     switch_res = "switch_dir::error::target dir doesn't exist"
    138             else:
    139                 switch_res = "switch_dir::error::target dir doesn't exist"
    140         self.request.send(switch_res.encode())
    141 
    142     def rmdir(self,*args):
    143         cmd_dic = args[0]
    144         action = cmd_dic["action"]
    145         filename = cmd_dic["filename"]
    146         back = ''
    147         if os.path.isdir("%s/%s" %(self.cur_path,filename)):
    148             print(self.cur_path)
    149             os.rmdir("%s/%s" %(self.cur_path,filename))
    150             back = "目录删除成功!"
    151         elif os.path.exists("%s/%s" %(self.cur_path,filename)):
    152             os.remove("%s/%s" %(self.cur_path,filename))
    153             back = "文件删除成功!"
    154         else:
    155             back = "文件或目录不存在!"
    156         self.request.send(back.encode())
    157 
    158     def mkdir(self,*args):
    159         cmd_dic = args[0]
    160         action = cmd_dic["action"]
    161         filename = cmd_dic["filename"]
    162         back = ''
    163         print(self.cur_path)
    164         print(self.home_path)
    165         if self.cur_path.startswith(self.home_path):
    166             os.mkdir(filename)
    167             back = "目录创建成功!"
    168         else:
    169             back = "没有权限在此目录创建目录!"
    170         self.request.send(back.encode())
    171 
    172     def handle(self):
    173         self.request.send(b"Welcome, ftp version 0.0.1")
    174         while True:
    175             try:
    176                 self.data = self.request.recv(1024).strip()
    177                 print("{} wrote:".format(self.client_address[0]))
    178                 print(self.data)
    179                 cmd_dic = json.loads(self.data.decode())
    180                 action = cmd_dic["action"]
    181                 if hasattr(self,action):
    182                     func = getattr(self,action)
    183                     func(cmd_dic)
    184             except ConnectionResetError as e :
    185                 print("客户端已断开!",e)
    186                 break
    187 
    188 if __name__ == "__main__":
    189     HOST, PORT = "localhost", 9999
    190     # server = socketserver.TCPServer((HOST, PORT), MyTCPHandler)  #单线程
    191     server = socketserver.ThreadingTCPServer((HOST, PORT), MyTCPHandler)   #多线程并发,没来一个请求服务器就会开启一个独立的线程
    192     server.serve_forever()
    ftp_server
     1 accounts = {
     2     'zz': {'passwd': "123",
     3              'quotation': 100000000,
     4              'home': 'home/zz'
     5              },
     6     'jj':{'passwd': "123",
     7              'quotation': 1000000,
     8              'home': 'home/jj'
     9              },
    10 }
    user_data

    四、效果展示

    1、用户登陆认证:

    2、多用户同时登录

    3、不同用户家目录不同

    4、查看目录下文件

    5、在家目录下切换目录

    6、在家目录下任意目录里创建目录

    7、删除目录或文件

    8、用户磁盘配额

    9、上传:支持断点续传

    10、下载:支持断点续传和进度条显示

  • 相关阅读:
    react——axios 和fetch-jsonp
    react——路由跳转、动态路由、get传值
    react——生命周期函数
    设置文字在水平垂直居中-高度自动撑开的块级元素也可以
    react——父子组件通信
    react-todoList
    react中获取输入框中值的两种方式——受控组件和非受控组件
    react中事件的使用
    asp.net core mvc视频A:笔记6-1.应用发布与部署
    asp.net core mvc视频A:笔记5-1.路由规则
  • 原文地址:https://www.cnblogs.com/hy0822/p/9224571.html
Copyright © 2011-2022 走看看