zoukankan      html  css  js  c++  java
  • Python实现FTP服务功能

    本文从以下三个方面, 阐述Python如何搭建FTP服务器

    一. Python搭建FTP服务器

    二. FTP函数释义

    三. 查看目录结构

    四. 上传下载程序

    一. Python搭建FTP服务器

    1. 搭建FTP服务器的Server端

    # -*- coding:utf-8 -*-
    from pyftpdlib.authorizers import DummyAuthorizer
    from  pyftpdlib.handlers  import FTPHandler
    from  pyftpdlib.servers import FTPServer
    # 实例化DummyAuthorizer来创建ftp用户
    authorizer = DummyAuthorizer()
    # 参数:用户名,密码,目录,权限
    authorizer.add_user('admin', '123456', r'C:UsersAdministratorDesktopftp', perm='elradfmwMT')
    # 匿名登录
    # authorizer.add_anonymous('/home/nobody')
    handler = FTPHandler
    handler.authorizer = authorizer
    # 参数:IP,端口,handler
    server = FTPServer(('0.0.0.0', 2121), handler)           #设置为0.0.0.0为本机的IP地址
    server.serve_forever()

    2. FTP服务器的客户端连接

    # -*- coding: utf-8 -*-
    from ftplib import FTP
    import time,tarfile,os
    
    
    #连接ftp
    def ftpconnect(host,port, username, password):
        ftp = FTP()
        # 打开调试级别2,显示详细信息
        # ftp.set_debuglevel(2)
        ftp.connect(host, port)
        ftp.login(username, password)
        return ftp
    
    #从ftp下载文件
    def downloadfile(ftp, remotepath, localpath):
        # 设置的缓冲区大小
        bufsize = 1024
        fp = open(localpath, 'wb')
        ftp.retrbinary('RETR ' + remotepath, fp.write, bufsize)
        ftp.set_debuglevel(0)# 参数为0,关闭调试模式
        fp.close()
    
    #从本地上传文件到ftp
    def uploadfile(ftp, remotepath, localpath):
        bufsize = 1024
        fp = open(localpath, 'rb')
        ftp.storbinary('STOR ' + remotepath, fp, bufsize)
        ftp.set_debuglevel(0)
        fp.close()
    
    if __name__ == "__main__":
        #host,port, username, password
        ftp = ftpconnect("192.168.10.113", 2121,"admin", "123456")
        #下载文件,第一个是ftp服务器路径下的文件,第二个是要下载到本地的路径文件
        downloadfile(ftp, "/12.mp3", r"C:UsersAdministratorDesktopftpdownload	est.mp3")
        # 上传文件,第一个是要上传到ftp服务器路径下的文件,第二个是本地要上传的的路径文件
        uploadfile(ftp, '/upload/1.txt', "C:/Users/Administrator/Desktop/1.txt")
        # ftp.close() #关闭ftp
        # #调用本地播放器播放下载的视频
        # os.system('start D:softkugouKGMusicKuGou.exe C:UsersAdministratorDesktopftp	est.mp3')
    
        print(ftp.getwelcome())# 打印出欢迎信息
        # 获取当前路径
        pwd_path = ftp.pwd()
        print("FTP当前路径:", pwd_path)
        # 显示目录下所有目录信息
        # ftp.dir()
        # 设置FTP当前操作的路径
        ftp.cwd('/upload/')
        # 返回一个文件名列表
        filename_list = ftp.nlst()
        print(filename_list)
    
        ftp.mkd('目录名')# 新建远程目录
        ftp.rmd('目录名')  # 删除远程目录
        ftp.delete('文件名')  # 删除远程文件
        ftp.rename('fromname', 'toname')  # 将fromname修改名称为toname
    
        # 逐行读取ftp文本文件
        file = '/upload/1.txt'
        # ftp.retrlines('RETR %s' % file)
        #与 retrlines()类似,只是这个指令处理二进制文件。回调函数 cb 用于处理每一块(块大小默认为 8KB)下载的数据
        # ftp.retrbinary('RETR %s' % file) 

    二. FTP函数释义

    Python中默认安装的ftplib模块定义了FTP类,其中函数有限,可用来实现简单的ftp客户端,用于上传或下载文件,函数列举如下

    ftp登陆连接
    from ftplib import FTP            #加载ftp模块
    ftp=FTP()                         #设置变量
    ftp.set_debuglevel(2)             #打开调试级别2,显示详细信息
    ftp.connect("IP","port")          #连接的ftp sever和端口
    ftp.login("user","password")      #连接的用户名,密码
    print ftp.getwelcome()            #打印出欢迎信息
    ftp.cmd("xxx/xxx")                #进入远程目录
    bufsize=1024                      #设置的缓冲区大小
    filename="filename.txt"           #需要下载的文件
    file_handle=open(filename,"wb").write #以写模式在本地打开文件
    ftp.retrbinaly("RETR filename.txt",file_handle,bufsize) #接收服务器上文件并写入本地文件
    ftp.set_debuglevel(0)             #关闭调试模式
    ftp.quit()                        #退出ftp
    
    ftp相关命令操作
    ftp.cwd(pathname)                 #设置FTP当前操作的路径
    ftp.dir()                         #显示目录下所有目录信息
    ftp.nlst()                        #获取目录下的文件
    ftp.mkd(pathname)                 #新建远程目录
    ftp.pwd()                         #返回当前所在位置
    ftp.rmd(dirname)                  #删除远程目录
    ftp.delete(filename)              #删除远程文件
    ftp.rename(fromname, toname)#将fromname修改名称为toname。
    ftp.storbinaly("STOR filename.txt",file_handel,bufsize)  #上传目标文件
    ftp.retrbinary("RETR filename.txt",file_handel,bufsize)  #下载FTP文件

    FTP.quit()与FTP.close()的区别

    FTP.quit():发送QUIT命令给服务器并关闭掉连接。这是一个比较“缓和”的关闭连接方式,但是如果服务器对QUIT命令返回错误时,会抛出异常。

    FTP.close():单方面的关闭掉连接,不应该用在已经关闭的连接之后,例如不应用在FTP.quit()之后。

    FTP对象方法说明
    
    login(user=’anonymous’,passwd=”, acct=”) 登录 FTP 服务器,所有参数都是可选的
    pwd() 获得当前工作目录
    cwd(path) 把当前工作目录设置为 path 所示的路径
    dir ([path[,…[,cb]]) 显示 path 目录里的内容,可选的参数 cb 是一个回调函数,会传递给 retrlines()方法
    nlst ([path[,…]) 与 dir()类似, 但返回一个文件名列表,而不是显示这些文件名
    retrlines(cmd [, cb]) 给定 FTP命令(如“ RETR filename”),用于下载文本文件。可选的回调函数 cb 用于处理文件的每一行
    retrbinary(cmd,cb[,bs=8192[, ra]]) 与 retrlines()类似,只是这个指令处理二进制文件。回调函数 cb 用于处理每一块(块大小默认为 8KB)下载的数据
    storlines(cmd, f) 给定 FTP 命令(如“ STOR filename”),用来上传文本文件。要给定一个文件对象 f
    storbinary(cmd, f,[,bs=8192]) 与 storlines()类似,只是这个指令处理二进制文件。要给定一个文件对象 f,上传块大小 bs 默认为 8KB
    rename(old, new) 把远程文件 old 重命名为 new
    delete(path) 删除位于 path 的远程文件
    mkd(directory) 创建远程目录
    rmd(directory) 删除远程目录
    quit() 关闭连接并退出

    三. 查看目录结构

    ftp.dir() 能显示目录下的文件信息,考虑到要分别对文件夹个数和文件数目进行统计,文件夹下存在文件夹和文件嵌套;将dir()后的目录信息放入列表,对列表进行操作;进入子文件夹后进行递归调用操作。

    # -*- coding: utf-8 -*-
     
    from ftplib import FTP
     
    ftp = FTP()
    ftp.connect('132.121.xx.xxx', 'xx909')
    ftp.login('crmyun_xxx', 'wyjjjjxJ')
    sum1 = 0
    sum2 = 0
    value = 0
     
    def search_file(start_dir):
     ftp.cwd(start_dir)
     print ftp.pwd()
     dir_res = []
     ftp.dir('.', dir_res.append) #对当前目录进行dir(),将结果放入列表
     for i in dir_res:
      if i.startswith("d"):
       global sum1 
       sum1 += 1
       search_file(ftp.pwd()+"/"+i.split(" ")[-1])
       ftp.cwd('..')
      else:
       global sum2, value
       sum2 += 1
       val = i.split(" ")[-1]
       value += ftp.size(val)
       if ftp.pwd().endswith('/'):    
    #    print ftp.pwd()+val+"  "+str(ftp.size(val))+" B" #打印出每个文件路径和大小
        pass
       else:    
    #    print ftp.pwd()+"/"+val+"  "+str(ftp.size(val))+" B"
        pass
    def sum_file(file_path):
     search_file(file_path)
     print "folder number is "+str(sum1)+", file number is "+str(sum2)+", Totle size is "+str(value)+" B"
      
     
    if __name__ == '__main__':
     sum_file("/apps/crmyun/crmyun_755")

    展示结果:

    四. 上传下载程序

    完整上传程序

    Python中默认安装的ftplib模块定义了FTP类,其中函数有限,可用来实现简单的ftp客户端,用于上传或下载文件

    # coding: utf-8
    from ftplib import FTP
    import time
    import tarfile
    import os
    # !/usr/bin/python
    # -*- coding: utf-8 -*-
     
    from ftplib import FTP
     
    def ftpconnect(host, username, password):
     ftp = FTP()
     # ftp.set_debuglevel(2)
     ftp.connect(host, 21)
     ftp.login(username, password)
     return ftp
     
    #从ftp下载文件
    def downloadfile(ftp, remotepath, localpath):
     bufsize = 1024
     fp = open(localpath, 'wb')
     ftp.retrbinary('RETR ' + remotepath, fp.write, bufsize)
     ftp.set_debuglevel(0)
     fp.close()
     
    #从本地上传文件到ftp
    def uploadfile(ftp, remotepath, localpath):
     bufsize = 1024
     fp = open(localpath, 'rb')
     ftp.storbinary('STOR ' + remotepath, fp, bufsize)
     ftp.set_debuglevel(0)
     fp.close()
     
    if __name__ == "__main__":
     ftp = ftpconnect("113.105.139.xxx", "ftp***", "Guest***")
     downloadfile(ftp, "Faint.mp4", "C:/Users/Administrator/Desktop/test.mp4")
     #调用本地播放器播放下载的视频
     os.system('start "C:Program FilesWindows Media Playerwmplayer.exe" "C:/Users/Administrator/Desktop/test.mp4"')
     uploadfile(ftp, "C:/Users/Administrator/Desktop/test.mp4", "test.mp4")
     
     ftp.quit()

    server main 代码:

    # _*_ coding:utf-8 _*_
    import os, sys, json, hashlib, socketserver, time
     
    base_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
    sys.path.append(base_dir)
    from conf import userdb_set
    class Ftp_server(socketserver.BaseRequestHandler):
     user_home_dir = ''
     def auth(self, *args):
      '''验证用户名及密码'''
      cmd_dic = args[0]
      username = cmd_dic["username"]
      password = cmd_dic["password"]
      f = open(userdb_set.userdb_set(), 'r')
      user_info = json.load(f)
      if username in user_info.keys():
       if password == user_info[username]:
        self.request.send('0'.encode())
        os.chdir('/home/%s' % username)
        self.user_home_dir = os.popen('pwd').read().strip()
        data = "%s login successed" % username
        self.loging(data)
       else:
        self.request.send('1'.encode())
        data = "%s login failed" % username
        self.loging(data)
        f.close
      else:
       self.request.send('1'.encode())
       data = "%s login failed" % username
       self.loging(data)
       f.close
       ##########################################
     
     def get(self, *args):
      '''给客户端传输文件'''
      request_code = {
       '0': 'file is ready to get',
       '1': 'file not found!'
      }
      cmd_dic = args[0]
      self.loging(json.dumps(cmd_dic))
      filename = cmd_dic["filename"]
      if os.path.isfile(filename):
       self.request.send('0'.encode('utf-8')) # 确认文件存在
       self.request.recv(1024)
       self.request.send(str(os.stat(filename).st_size).encode('utf-8'))
       self.request.recv(1024)
       m = hashlib.md5()
       f = open(filename, 'rb')
       for line in f:
        m.update(line)
        self.request.send(line)
       self.request.send(m.hexdigest().encode('utf-8'))
       print('From server:Md5 value has been sended!')
       f.close()
      else:
       self.request.send('1'.encode('utf-8'))
       ###########################################
     
     def cd(self, *args):
      '''执行cd命令'''
      user_current_dir = os.popen('pwd').read().strip()
      cmd_dic = args[0]
      self.loging(json.dumps(cmd_dic))
      path = cmd_dic['path']
      if path.startswith('/'):
       if self.user_home_dir in path:
        os.chdir(path)
        new_dir = os.popen('pwd').read()
        user_current_dir = new_dir
        self.request.send('Change dir successfully!'.encode("utf-8"))
        data = 'Change dir successfully!'
        self.loging(data)
       elif os.path.exists(path):
        self.request.send('Permission Denied!'.encode("utf-8"))
        data = 'Permission Denied!'
        self.loging(data)
       else:
        self.request.send('Directory not found!'.encode("utf-8"))
        data = 'Directory not found!'
        self.loging(data)
      elif os.path.exists(path):
       os.chdir(path)
       new_dir = os.popen('pwd').read().strip()
       if self.user_home_dir in new_dir:
        self.request.send('Change dir successfully!'.encode("utf-8"))
        user_current_dir = new_dir
        data = 'Change dir successfully!'
        self.loging(data)
       else:
        os.chdir(user_current_dir)
        self.request.send('Permission Denied!'.encode("utf-8"))
        data = 'Permission Denied!'
        self.loging(data)
      else:
       self.request.send('Directory not found!'.encode("utf-8"))
       data = 'Directory not found!'
       self.loging(data)
       ###########################################
     
     def rm(self, *args):
      request_code = {
       '0': 'file exist,and Please confirm whether to rm',
       '1': 'file not found!'
      }
      cmd_dic = args[0]
      self.loging(json.dumps(cmd_dic))
      filename = cmd_dic['filename']
      if os.path.exists(filename):
       self.request.send('0'.encode("utf-8")) # 确认文件存在
       client_response = self.request.recv(1024).decode()
       if client_response == '0':
        os.popen('rm -rf %s' % filename)
        self.request.send(('File %s has been deleted!' % filename).encode("utf-8"))
        self.loging('File %s has been deleted!' % filename)
       else:
        self.request.send(('File %s not deleted!' % filename).encode("utf-8"))
        self.loging('File %s not deleted!' % filename)
      else:
       self.request.send('1'.encode("utf-8"))
       ########################################
     
     def pwd(self, *args):
      '''执行pwd命令'''
      cmd_dic = args[0]
      self.loging(json.dumps(cmd_dic))
      server_response = os.popen('pwd').read().strip().encode("utf-8")
      self.request.send(server_response)
     
     #############################################
     def ls(self, *args):
      '''执行ls命名'''
      cmd_dic = args[0]
      self.loging(json.dumps(cmd_dic))
      path = cmd_dic['path']
      cmd = 'ls -l %s' % path
      server_response = os.popen(cmd).read().encode("utf-8")
      self.request.send(server_response)
     
     ############################################
     def put(self, *args):
      '''接收客户端文件'''
      cmd_dic = args[0]
      self.loging(json.dumps(cmd_dic))
      filename = cmd_dic["filename"]
      filesize = cmd_dic["size"]
      if os.path.isfile(filename):
       f = open(filename + '.new', 'wb')
      else:
       f = open(filename, 'wb')
      request_code = {
       '200': 'Ready to recceive data!',
       '210': 'Not ready to received data!'
      }
      self.request.send('200'.encode())
      receive_size = 0
      while True:
       if receive_size < filesize:
        data = self.request.recv(1024)
        f.write(data)
        receive_size += len(data)
       else:
        data = "File %s has been uploaded successfully!" % filename
        self.loging(data)
        print(data)
        break
     
        ################################################
     
     def mkdir(self, *args):
      request_code = {
       '0': 'Directory has been made!',
       '1': 'Directory is aleady exist!'
      }
      cmd_dic = args[0]
      self.loging(json.dumps(cmd_dic))
      dir_name = cmd_dic['dir_name']
      if os.path.exists(dir_name):
       self.request.send('1'.encode("utf-8"))
      else:
       os.popen('mkdir %s' % dir_name)
       self.request.send('0'.encode("utf-8"))
     
       #############################################
     
      def loging(self, data):
      '''日志记录'''
      localtime = time.asctime(time.localtime(time.time()))
      log_file = '/root/ftp/ftpserver/log/server.log'
      with open(log_file, 'a', encoding='utf-8') as f:
       f.write('%s-->' % localtime + data + '
    ')
       ##############################################
     
     def handle(self):
      # print("您本次访问使用的IP为:%s" %self.client_address[0])
      # localtime = time.asctime( time.localtime(time.time()))
      # print(localtime)
     
      while True:
       try:
        self.data = self.request.recv(1024).decode() #
        # print(self.data)
        cmd_dic = json.loads(self.data)
        action = cmd_dic["action"]
        # print("用户请求%s"%action)
        if hasattr(self, action):
         func = getattr(self, action)
         func(cmd_dic)
       except Exception as e:
        self.loging(str(e))
        break
     
    def run():
     HOST, PORT = '0.0.0.0', 6969
     print("The server is started,and listenning at port 6969")
     server = socketserver.ThreadingTCPServer((HOST, PORT), Ftp_server)
     server.serve_forever()
    if __name__ == '__main__':
     run()

    设置用户口令代码:

    #_*_ coding:utf-8 _*_
    import os,json,hashlib,sys
     
    base_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
    userdb_file = base_dir+"data\userdb"
    # print(userdb_file)
    def userdb_set():
     if os.path.isfile(userdb_file):
      # print(userdb_file)
      return userdb_file
     else:
      print('请先为您的服务器创建用户!')
      user_data = {}
      dict={}
      Exit_flags = True
      while Exit_flags:
       username = input("Please input username:")
       if username != 'exit':
        password = input("Please input passwod:")
        if password != 'exit':
          user_data.update({username:password})
          m = hashlib.md5()
          # m.update('hello')
          # print(m.hexdigest())
          for i in user_data:
           # print(i,user_data[i])
           m.update(user_data[i].encode())
           dict.update({i:m.hexdigest()})
        else:
         break
       else:
        break
      f = open(userdb_file,'w')
      json.dump(dict,f)
      f.close()
     return userdb_file

    参考文章:

    python的ftplib包介绍:https://docs.python.org/3/library/ftplib.html
    https://blog.csdn.net/xc_zhou/article/details/81021414
    https://www.jb51.net/article/142388.htm
    https://www.jb51.net/article/109429.htm
    https://www.cnblogs.com/hltswd/p/6228992.html

  • 相关阅读:
    TypeError: translate() takes exactly one argument (2 given)
    matlab为long term visual tracking数据集生成groundtruth.txt
    Linux下为python3安装opencv
    tensorflow全连接层降维
    MDNet结果json文件转成long term visual tracking (oxuva)评估所需的csv文件的python脚本
    no module named caffe
    IIS短文件/文件夹泄露漏洞
    点击劫持漏洞
    WPF Combobox数据绑定 Binding
    关于Win10安装vs2013简体中文语言包无法安装的问题
  • 原文地址:https://www.cnblogs.com/huzixia/p/10389945.html
Copyright © 2011-2022 走看看