教程集 www.jiaochengji.com
教程集 >  Python编程  >  Python入门  >  正文 Python实现的简易FTP

Python实现的简易FTP

发布时间:2021-12-29   编辑:jiaochengji.com
教程集为您提供Python实现的简易FTP等资源,欢迎您收藏本站,我们将为您提供最新的Python实现的简易FTP资源

Python版本 

实现了比之前的xxftp更多更完善的功能 

1、继续支持多用户 

2、继续支持虚拟目录 

3、增加支持用户根目录以及映射虚拟目录的权限设置 

4、增加支持限制用户根目录或者虚拟目录的空间大小 

xxftp的特点 

1、开源、跨平台 

2、简单、易用 

3、不需要数据库 

4、可扩展性超强 

5、你可以免费使用xxftp假设自己的私人FTP服务器 

匿名帐号可以使用! 

匿名根目录只读,映射了一个虚拟目录,可以上传文件但不允许更改! 

使用方法 

跟用C语言写的xxftp使用方法一样

FTP服务器目录结构

<pre class="brush:php;toolbar:false">-/root  -xxftp.welcome  -xxftp.goodbye  -user1  -.xxftp  -password  -...  -user2  -.xxftp  -password  -...  -anonymous源代码</pre>

代码如下:

<pre class="brush:php;toolbar:false">import socket, threading, os, sys, time  import hashlib, platform, stat  listen_ip = "localhost"  listen_port = 21  conn_list = []  root_dir = "./home"  max_connections = 500  conn_timeout = 120  class FtpConnection(threading.Thread):  def __init__(self, fd):  threading.Thread.__init__(self)  self.fd = fd  self.running = True  self.setDaemon(True)  self.alive_time = time.time()  self.option_utf8 = False  self.identified = False  self.option_pasv = True  self.username = ""  def process(self, cmd, arg):  cmd = cmd.upper();  if self.option_utf8:  arg = unicode(arg, "utf8").encode(sys.getfilesystemencoding())  print "<<", cmd, arg, self.fd  # Ftp Command  if cmd == "BYE" or cmd == "QUIT":  if os.path.exists(root_dir   "/xxftp.goodbye"):  self.message(221, open(root_dir   "/xxftp.goodbye").read())  else:  self.message(221, "Bye!")  self.running = False  return  elif cmd == "USER":  # Set Anonymous User  if arg == "": arg = "anonymous"  for c in arg:  if not c.isalpha() and not c.isdigit() and c!="_":  self.message(530, "Incorrect username.")  return  self.username = arg  self.home_dir = root_dir   "/"   self.username  self.curr_dir = "/"  self.curr_dir, self.full_path, permission, self.vdir_list, \  limit_size, is_virtual = self.parse_path("/")  if not os.path.isdir(self.home_dir):  self.message(530, "User "   self.username   " not exists.")  return  self.pass_path = self.home_dir   "/.xxftp/password"  if os.path.isfile(self.pass_path):  self.message(331, "Password required for "   self.username)  else:  self.message(230, "Identified!")  self.identified = True  return  elif cmd == "PASS":  if open(self.pass_path).read() == hashlib.md5(arg).hexdigest():  self.message(230, "Identified!")  self.identified = True  else:  self.message(530, "Not identified!")  self.identified = False  return  elif not self.identified:  self.message(530, "Please login with USER and PASS.")  return  self.alive_time = time.time()  finish = True  if cmd == "NOOP":  self.message(200, "ok")  elif cmd == "TYPE":  self.message(200, "ok")  elif cmd == "SYST":  self.message(200, "UNIX")  elif cmd == "EPSV" or cmd == "PASV":  self.option_pasv = True  try:  self.data_fd = socket.socket(socket.AF_INET, socket.SOCK_STREAM)  self.data_fd.bind((listen_ip, 0))  self.data_fd.listen(1)  ip, port = self.data_fd.getsockname()  if cmd == "EPSV":  self.message(229, "Entering Extended Passive Mode (|||"   str(port)   "|)")  else:  ipnum = socket.inet_aton(ip)  self.message(227, "Entering Passive Mode (%s,%u,%u)." %  (",".join(ip.split(".")), (port>>8&0xff), (port&0xff)))  except:  self.message(500, "failed to create data socket.")  elif cmd == "EPRT":  self.message(500, "implement EPRT later...")  elif cmd == "PORT":  self.option_pasv = False  self.data_fd = socket.socket(socket.AF_INET, socket.SOCK_STREAM)  s = arg.split(",")  self.data_ip = ".".join(s[:4])  self.data_port = int(s[4])*256   int(s[5])  self.message(200, "ok")  elif cmd == "PWD" or cmd == "XPWD":  if self.curr_dir == "": self.curr_dir = "/"  self.message(257, '"'   self.curr_dir   '"')  elif cmd == "LIST" or cmd == "NLST":  if arg != "" and arg[0] == "-": arg = "" # omit parameters  remote, local, perm, vdir_list, limit_size, is_virtual = self.parse_path(arg)  if not os.path.exists(local):  self.message(550, "failed.")  return  if not self.establish(): return  self.message(150, "ok")  for v in vdir_list:  f = v[0]  if self.option_utf8:  f = unicode(f, sys.getfilesystemencoding()).encode("utf8")  if cmd == "NLST":  info = f   "\r\n"  else:  info = "d%s%s------- u %8s %8s %8lu %s %s\r\n" % (  "r" if "read" in perm else "-",  "w" if "write" in perm else "-",  1, "0", "0", 0,  time.strftime("%b %d %Y", time.localtime(time.time())),  f)  self.data_fd.send(info)  for f in os.listdir(local):  if f[0] == ".": continue  path = local   "/"   f  if self.option_utf8:  f = unicode(f, sys.getfilesystemencoding()).encode("utf8")  if cmd == "NLST":  info = f   "\r\n"  else:  st = os.stat(path)  info = "%s%s%s------- u %8s %8s %8lu %s %s\r\n" % (  "-" if os.path.isfile(path) else "d",  "r" if "read" in perm else "-",  "w" if "write" in perm else "-",  1, "0", "0", st[stat.ST_SIZE],  time.strftime("%b %d %Y", time.localtime(st[stat.ST_MTIME])),  f)  self.data_fd.send(info)  self.message(226, "Limit size: "   str(limit_size))  self.data_fd.close()  self.data_fd = 0  elif cmd == "REST":  self.file_pos = int(arg)  self.message(250, "ok")  elif cmd == "FEAT":  features = "211-Features:\r\nSITES\r\nEPRT\r\nEPSV\r\nMDTM\r\nPASV\r\n"\  "REST STREAM\r\nSIZE\r\nUTF8\r\n211 End\r\n"  self.fd.send(features)  elif cmd == "OPTS":  arg = arg.upper()  if arg == "UTF8 ON":  self.option_utf8 = True  self.message(200, "ok")  elif arg == "UTF8 OFF":  self.option_utf8 = False  self.message(200, "ok")  else:  self.message(500, "unrecognized option")  elif cmd == "CDUP":  finish = False  arg = ".."  else:  finish = False  if finish: return  # Parse argument ( It's a path )  if arg == "":  self.message(500, "where's my argument?")  return  remote, local, permission, vdir_list, limit_size, is_virtual = \  self.parse_path(arg)  # can not do anything to virtual directory  if is_virtual: permission = "none"  can_read, can_write, can_modify = "read" in permission, "write" in permission, "modify" in permission  newpath = local  try:  if cmd == "CWD":  if(os.path.isdir(newpath)):  self.curr_dir = remote  self.full_path = newpath  self.message(250, '"'   remote   '"')  else:  self.message(550, "failed")  elif cmd == "MDTM":  if os.path.exists(newpath):  self.message(213, time.strftime("%Y%m%d%I%M%S", time.localtime(  os.path.getmtime(newpath))))  else:  self.message(550, "failed")  elif cmd == "SIZE":  self.message(231, os.path.getsize(newpath))  elif cmd == "XMKD" or cmd == "MKD":  if not can_modify:  self.message(550, "permission denied.")  return  os.mkdir(newpath)  self.message(250, "ok")  elif cmd == "RNFR":  if not can_modify:  self.message(550, "permission denied.")  return  self.temp_path = newpath  self.message(350, "rename from "   remote)  elif cmd == "RNTO":  os.rename(self.temp_path, newpath)  self.message(250, "RNTO to "   remote)  elif cmd == "XRMD" or cmd == "RMD":  if not can_modify:  self.message(550, "permission denied.")  return  os.rmdir(newpath)  self.message(250, "ok")  elif cmd == "DELE":  if not can_modify:  self.message(550, "permission denied.")  return  os.remove(newpath)  self.message(250, "ok")  elif cmd == "RETR":  if not os.path.isfile(newpath):  self.message(550, "failed")  return  if not can_read:  self.message(550, "permission denied.")  return  if not self.establish(): return  self.message(150, "ok")  f = open(newpath, "rb")  while self.running:  self.alive_time = time.time()  data = f.read(8192)  if len(data) == 0: break  self.data_fd.send(data)  f.close()  self.data_fd.close()  self.data_fd = 0  self.message(226, "ok")  elif cmd == "STOR" or cmd == "APPE":  if not can_write:  self.message(550, "permission denied.")  return  if os.path.exists(newpath) and not can_modify:  self.message(550, "permission denied.")  return  # Check space size remained!  used_size = 0  if limit_size > 0:  used_size = self.get_dir_size(os.path.dirname(newpath))  if not self.establish(): return  self.message(150, "ok")  f = open(newpath, ("ab" if cmd == "APPE" else "wb") )  while self.running:  self.alive_time = time.time()  data = self.data_fd.recv(8192)  if len(data) == 0: break  if limit_size > 0:  used_size = used_size   len(data)  if used_size > limit_size: break  f.write(data)  f.close()  self.data_fd.close()  self.data_fd = 0  if limit_size > 0 and used_size > limit_size:  self.message(550, "Exceeding user space limit: "   str(limit_size)   " bytes")  else:  self.message(226, "ok")  else:  self.message(500, cmd   " not implemented")  except:  self.message(550, "failed.")  def establish(self):  if self.data_fd == 0:  self.message(500, "no data connection")  return False  if self.option_pasv:  fd = self.data_fd.accept()[0]  self.data_fd.close()  self.data_fd = fd  else:  try:  self.data_fd.connect((self.data_ip, self.data_port))  except:  self.message(500, "failed to establish data connection")  return False  return True  def read_virtual(self, path):  vdir_list = []  path = path   "/.xxftp/virtual"  if os.path.isfile(path):  for v in open(path, "r").readlines():  items = v.split()  items[1] = items[1].replace("$root", root_dir)  vdir_list.append(items)  return vdir_list  def get_dir_size(self, folder):  size = 0  for path, dirs, files in os.walk(folder):  for f in files:  size  = os.path.getsize(os.path.join(path, f))  return size  def read_size(self, path):  size = 0  path = path   "/.xxftp/size"  if os.path.isfile(path):  size = int(open(path, "r").readline())  return size  def read_permission(self, path):  permission = "read,write,modify"  path = path   "/.xxftp/permission"  if os.path.isfile(path):  permission = open(path, "r").readline()  return permission  def parse_path(self, path):  if path == "": path = "."  if path[0] != "/":  path = self.curr_dir   "/"   path  s = os.path.normpath(path).replace("\\", "/").split("/")  local = self.home_dir  # reset directory permission  vdir_list = self.read_virtual(local)  limit_size = self.read_size(local)  permission = self.read_permission(local)  remote = ""  is_virtual = False  for name in s:  name = name.lstrip(".")  if name == "": continue  remote = remote   "/"   name  is_virtual = False  for v in vdir_list:  if v[0] == name:  permission = v[2]  local = v[1]  limit_size = self.read_size(local)  is_virtual = True  if not is_virtual: local = local   "/"   name  vdir_list = self.read_virtual(local)  return (remote, local, permission, vdir_list, limit_size, is_virtual)  def run(self):  ''' Connection Process '''  try:  if len(conn_list) > max_connections:  self.message(500, "too many connections!")  self.fd.close()  self.running = False  return  # Welcome Message  if os.path.exists(root_dir   "/xxftp.welcome"):  self.message(220, open(root_dir   "/xxftp.welcome").read())  else:  self.message(220, "xxftp(Python) www.xiaoxia.org")  # Command Loop  line = ""  while self.running:  data = self.fd.recv(4096)  if len(data) == 0: break  line  = data  if line[-2:] != "\r\n": continue  line = line[:-2]  space = line.find(" ")  if space == -1:  self.process(line, "")  else:  self.process(line[:space], line[space 1:])  line = ""  except:  print "error", sys.exc_info()  self.running = False  self.fd.close()  print "connection end", self.fd, "user", self.username  def message(self, code, s):  ''' Send Ftp Message '''  s = str(s).replace("\r", "")  ss = s.split("\n")  if len(ss) > 1:  r = (str(code)   "-")   ("\r\n"   str(code)   "-").join(ss[:-1])  r  = "\r\n"   str(code)   " "   ss[-1]   "\r\n"  else:  r = str(code)   " "   ss[0]   "\r\n"  if self.option_utf8:  r = unicode(r, sys.getfilesystemencoding()).encode("utf8")  self.fd.send(r)  def server_listen():  global conn_list  listen_fd = socket.socket(socket.AF_INET, socket.SOCK_STREAM)  listen_fd.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)  listen_fd.bind((listen_ip, listen_port))  listen_fd.listen(1024)  conn_lock = threading.Lock()  print "ftpd is listening on ", listen_ip   ":"   str(listen_port)  while True:  conn_fd, remote_addr = listen_fd.accept()  print "connection from ", remote_addr, "conn_list", len(conn_list)  conn = FtpConnection(conn_fd)  conn.start()  conn_lock.acquire()  conn_list.append(conn)  # check timeout  try:  curr_time = time.time()  for conn in conn_list:  if int(curr_time - conn.alive_time) > conn_timeout:  if conn.running == True:  conn.fd.shutdown(socket.SHUT_RDWR)  conn.running = False  conn_list = [conn for conn in conn_list if conn.running]  except:  print sys.exc_info()  conn_lock.release()  def main():  server_listen()  if __name__ == "__main__":  main()</pre>

您可能感兴趣的文章:
php ftp下载文件的代码一例
php使用ftp下载文件的简单例子
php ftp文件上传函数的简单例子
PHP的FTP学习(一)
php ftp类(上传、下载、复制、移动等)
php实现文件的自动ftp更新
php实现ftp上传的类与调用示例
python能做什么有趣的东西
php ftp函数应用(范例,ftp类,创建目录函数等)
php自定义ftp类与调用实例

[关闭]
~ ~