PythonがFTP機能を実装する方法

Pythonバージョン

以前のxxftpよりもますます完全な機能を実現

1、 複数のユーザーを引き続きサポート

2、 仮想ディレクトリのサポートを継続

3、 仮想ディレクトリをマッピングするためのユーザールートディレクトリと権限設定のサポートが追加されました

4、 ユーザーのルートディレクトリまたは仮想ディレクトリのスペースサイズを制限するためのサポートが追加されました

**xxftp **の機能

1、 オープンソース、クロスプラットフォーム

2、 シンプルで使いやすい

3、 データベースは必要ありません

4、 超スケーラビリティ

5、 独自のプライベートFTPサーバーを想定して、xxftpを無料で使用できます

匿名アカウントが利用できます!

匿名ルートディレクトリは読み取り専用で、仮想ディレクトリをマップします。ファイルはアップロードできますが、変更することはできません。

指示

C言語で書かれたxxftpと同じ方法を使用します

FTPサーバーのディレクトリ構造

- /root 
- xxftp.welcome 
- xxftp.goodbye 
- user1 
- . xxftp 
- password 
- ...- user2 
- . xxftp 
- password 
- ...- 匿名のソースコード

コードは次のように表示されます。

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()

コンテンツの拡張:

FTPサーバーコード:

import socket,os,time
import hashlib
server =socket.socket()
server.bind(('0.0.0.0',6666))
server.listen()print("待つ....")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() #指示とファイル名を記録する
print(filename)
# ファイルが現在のディレクトリに存在するかどうかを確認します。ファイルはディレクトリではなくファイルである必要があります
if os.path.isfile(filename):
f =open(filename,'rb')
# m = hashlib.md5() #md5を作成します
file_size = os.stat(filename).st_size #stat()ファイルのサイズを返すことができます
conn.send((str(file_size)).encode()) #送信ファイルサイズ
conn.recv(1024) #返品情報を待っています
for line in f:
# m.updata(line) 
conn.send(line)
# print("file md5",m.hexdigest()) #md5値を出力
f.close()

これで、PythonがFTP関数を実装する方法に関するこの記事は終わりです。Pythonによって実装されるより単純なFTPコンテンツについては、ZaLou.Cnを検索してください。

Recommended Posts

PythonがFTP機能を実装する方法
Pythonがメール機能を実装する方法
Pythonはftpファイル転送機能を実装しています
Pythonがタイマー機能を実装する方法
Pythonは画像スティッチング機能を実装しています
PythonはAIフェイスチェンジ機能を実装しています
pythonでid関数を実行する方法
pythonはどのように独自の関数を呼び出すのですか
Python enumerate()関数
Python関数バッファー
Pythonでzip関数を使用する方法
pythonでformat関数を使用する方法
Pythonはスーパーマリオを実装しています
Pythonはtic-tac-toeゲームを実装しています
Pythonカスタム関数の基本
Pythonはtic-tac-toeゲームを実装しています
Pythonの結合関数
Python組み込み関数-compile()
Pythonはマンマシンゴバンを実装します
Python関数の基礎学習
PythonはTetrisゲームを実装しています
Pythonデータ分析-関数の適用
Pythonは画像スティッチングを実装しています
Pythonはminesweeperゲームを実装しています
Pythonはスキャンツールを実装しています
pythonがどのように発明されたか
Pythonプリントプリントタイマー機能
Pythonはしきい値回帰を実装します
Pythonは地雷除去ゲームを実装しています
PythonがXMLを解析する方法
Pythonは電子辞書を実装しています
Pythonは推測ゲームを実装しています
PythonはFTPを実装して、ファイルをループでアップロードします
Pythonは関数メソッドを定義します
Pythonは単純なタンクバトルを実装します
Pythonの上位関数の使用法の概要!
Pythonはudpチャットウィンドウを実装します
pythonコードにコメントする方法
PythonはWeChat飛行機ゲームを実装しています
Pythonはオンライン翻訳機能を実現します
Pythonは単語推測ゲームを実装しています
Pythonが文字列の大文字小文字を変換する方法
Pythonは推測ゲームを実装しています
Pythonはどのように整数を出力しますか
pythonはどのようにバックスラッシュを出力しますか
Pythonは駐車場管理システムを実現
Pythonはデジタル爆弾ゲームを実装しています
PythonはTCPファイル転送を実装します
Pythonnumpyはローリングケースを実装します
pythonをすばやく学ぶ方法
OpenCVPythonはパズルゲームを実装しています
Pythonは単純なtic-tac-toeゲームを実装しています
Pythonはパスワード強度検証を実装します
Pythonは車の管理システムを実装しています
Pythonトルネードアップロードファイル機能
Pythonはコードブロックフォールディングを実装します
Pythonはパノラマ画像スティッチングを実装しています
Pythonマジック関数eval()学習
PythonはSMTPメール送信を実装します
Pythonは多次元配列ソートを実装しています
Pythonは平均シフトクラスタリングアルゴリズムを実装しています