How Python implements FTP function

Python version

Achieved more and more complete functions than the previous xxftp

1、 Continue to support multiple users

2、 Continue to support virtual directories

3、 Added support for user root directory and permission settings for mapping virtual directories

4、 Added support for limiting the space size of the user's root directory or virtual directory

Features of xxftp

1、 Open source, cross platform

2、 Simple and easy to use

3、 No database required

4、 Super scalability

5、 You can use xxftp for free assuming your own private FTP server

Anonymous account can be used!

The anonymous root directory is read-only and maps a virtual directory. Files can be uploaded but not changed!

Instructions

Use the same method as xxftp written in C language

FTP server directory structure

- /root 
- xxftp.welcome 
- xxftp.goodbye 
- user1 
- . xxftp 
- password 
- ...- user2 
- . xxftp 
- password 
- ...- anonymous source code

code show as below:

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 =120classFtpConnection(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":ifopen(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.")returnif 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------- %04u %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------- %04u %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")returnif not can_read: 
self.message(550,"permission denied.")returnif not self.establish():return 
self.message(150,"ok") 
f =open(newpath,"rb")while self.running: 
self.alive_time = time.time() 
data = f.read(8192)iflen(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.")returnif os.path.exists(newpath) and not can_modify: 
self.message(550,"permission denied.")return 
# Check space size remained! 
used_size =0if 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)iflen(data)==0:breakif 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 =0if 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 inopen(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 =0for 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:iflen(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)iflen(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")iflen(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:ifint(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()

Content expansion:

FTP server code:

import socket,os,time
import hashlib
server =socket.socket()
server.bind(('0.0.0.0',6666))
server.listen()print("wait....")while True:
conn,addr = server.accept()print("new conn:",conn)while True:
data = conn.recv(1024)if not data:print("client is disconnection")break
cmd,filename = data.decode().split() #Record instructions and file names
print(filename)
# Determine whether the file exists in the current directory, and it must be a file, not a directory
if os.path.isfile(filename):
f =open(filename,'rb')
# m = hashlib.md5() #Create md5
file_size = os.stat(filename).st_size #stat()Can return the size of the file
conn.send((str(file_size)).encode()) #Send file size
conn.recv(1024) #Waiting for return information
for line in f:
# m.updata(line) 
conn.send(line)
# print("file md5",m.hexdigest()) #Print md5 value
f.close()

So far this article on how Python implements the FTP function is introduced. For more simple FTP content implemented by Python, please search ZaLou.Cn

Recommended Posts

How Python implements FTP function
How Python implements the mail function
Python implements ftp file transfer function
How Python implements the timer function
Python implements image stitching function
Python implements AI face change function
How to run id function in python
How does python call its own function
Python enumerate() function
Python function buffer
How to use the zip function in Python
How to use the format function in python
Python implements Super Mario
Python implements tic-tac-toe game
Python custom function basics
Python implements tic-tac-toe game
Join function in Python
Python built-in function -compile()
Python implements man-machine gobang
Python function basic learning
Python implements Tetris game
Python data analysis-apply function
Python implements image stitching
Python implements minesweeper game
Python implements scanning tools
How python was invented
Python Print print timer function
Python implements threshold regression
Python implements minesweeper games
How Python parses XML
Python implements electronic dictionary
Python implements guessing game
Python implements FTP to upload files in a loop
Python defines a function method
Python implements simple tank battle
Python high-order function usage summary!
Python implements udp chat window
How to comment python code
Python implements WeChat airplane game
Python realizes online translation function
Python implements word guessing game
How Python converts string case
Python implements a guessing game
How does Python output integers
How does python output backslashes
Python implements parking management system
Python implements digital bomb game
Python implements TCP file transfer
Python numpy implements rolling case
How to learn python quickly
OpenCV Python implements puzzle games
Python implements simple tic-tac-toe game
Python implements password strength verification
Python implements car management system
Python tornado upload file function
Python implements code block folding
Python implements panoramic image stitching
Python magic function eval () learning
Python implements SMTP mail sending
Python implements multi-dimensional array sorting
Python implements mean-shift clustering algorithm