目的:实现客户端到服务器的上传功能
所需文件夹:
客户端是FTP_client 服务端是FTP_server
bin文件存放执行文件,conf下存放配置文件,core下是核心文件,home是家目录,logger存放日志文件.
客户端代码 ftp_client.py:
import optparse import socket import os,sys import json import time import hashlib STATUS_CODE = { 250: "Invalid cmd format,e.g:{'action':'get','filname':'test.py','size':344}", 251: "Incalid cmd", 252: "Invalid auth data", 253: "Wrong username or password", 254: "Passed authentication", 255: "Filename doesn't provided", 256: "Filename doesn't exist on the server", 257: "Ready to send file", 258: "md5 verification", 800: "The file exist,but not enough,is continue?", 801: "The file exist!", 802: "Ready to receive datas", 900: "md5 validate success" } class ClientHandler(): def __init__(self): self.op = optparse.OptionParser() self.op.add_option("-s","--server",dest="server") self.op.add_option("-P","--port",dest="port") self.op.add_option("-u","--username",dest="username") self.op.add_option("-p","--password",dest="password") self.options,self.args = self.op.parse_args() self.verify_args(self.options,self.args) self.make_connection() self.mainPath = os.path.dirname(os.path.abspath(__file__)) self.last = 0 def verify_args(self,options,args): server = options.server port = options.port username = options.username password = options.password if int(port)>0 and int(port)<65535: return True else: exit("The port is in 0~65535") def make_connection(self): self.sock = socket.socket() self.sock.connect((self.options.server,int(self.options.port))) def interactive(self): print("Begin to interactive...") if self.authenticate(): while True: cmd_info = input("[%s]"%self.current_dir).strip() cmd_list = cmd_info.split() if hasattr(self,cmd_list[0]): func = getattr(self,cmd_list[0]) func(*cmd_list) def put(self,*cmd_list): # put 12.jpg images action,local_path,target_path = cmd_list local_path=os.path.join(self.mainPath,local_path) file_name = os.path.basename(local_path) file_size = os.stat(local_path).st_size data = { "action": "put", "file_name": file_name, "file_size": file_size, "target_path": target_path } self.sock.send(json.dumps(data).encode('utf-8')) is_exist = self.sock.recv(1024).decode('utf-8') ###################### has_sent = 0 if is_exist=="800": #文件完整 choice = input("The file exist,but not enough,is continue?[Y/N]").strip() if choice.upper()=='Y': self.sock.sendall("Y".encode('utf-8')) continue_position = self.sock.recv(1024).decode('utf-8') has_sent+=int(continue_position) else: self.sock.sendall("N".encode('utf-8')) elif is_exist=="801": #文件完全存在 print('The file exist') return f = open(local_path,"rb") f.seek(has_sent) start = time.time() md5_obj = hashlib.md5() while has_sent<file_size: data = f.read(1024) self.sock.sendall(data) has_sent+=len(data) md5_obj.update(data) self.show_process(has_sent,file_size) else: print("post success!!!") md5_val = md5_obj.hexdigest() md5_server = self.sock.recv(1024).decode('utf-8') print(md5_server) self.sock.sendall(md5_val.encode('utf-8')) f.close() print("Put Success") def show_process(self,has,total): rate = float(has)/float(total) rate_num = int(rate*100) rate_num_1 = int(rate_num/2) if self.last!=rate_num: sys.stdout.write("%s%% %s "%(rate_num,"#"*rate_num_1)) self.last = rate_num def authenticate(self): if self.options.username is None or self.options.password is None: username = input('username: ') password = input('password: ') return self.get_auth_result(username,password) return self.get_auth_result(self.options.username,self.options.password) def response(self): data = self.sock.recv(1024).decode('utf-8') data = json.loads(data) return data def get_auth_result(self,user,pwd): data = { "action": "auth", "username": user, "password": pwd } self.sock.send(json.dumps(data).encode('utf-8')) response = self.response() print(response) if response["status_code"]==254: self.user = user self.current_dir = user print(STATUS_CODE[254]) return True else: print(STATUS_CODE[response["status_code"]]) def ls(self,*cmd_list): data = { "action":"ls", } self.sock.sendall(json.dumps(data).encode('utf-8')) data = self.sock.recv(1024).decode('utf-8') print(data) def cd(self,*cmd_list): data = { "action": "cd", "dirname": cmd_list[1], } self.sock.send(json.dumps(data).encode('utf-8')) data = self.sock.recv(1024).decode('utf-8') self.current_dir = self.user + "\" +os.path.basename(data) ch = ClientHandler() ch.interactive()
服务端代码 启动代码ftp_server.py
import os,sys BaseAddress = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) sys.path.append(BaseAddress) from core import main if __name__ == '__main__': main.ArgvHandler()
核心代码 main.py
import optparse import socketserver from conf import settings from core import server class ArgvHandler(): def __init__(self): self.op = optparse.OptionParser() # self.op.add_option('-s','--server',dest='server') # self.op.add_option('-P','--port',dest='port') # self.op.add_option('-s','--s',dest='server') options,args = self.op.parse_args() self.verify_args(options,args) def verify_args(self,options,args): cmd = args[0] if hasattr(self,cmd): func = getattr(self,cmd) func() def start(self): print('the server is working...') s = socketserver.ThreadingTCPServer((settings.IP,settings.PORT),server.SeverHandler) s.serve_forever() def help(self): pass
执行代码
import socketserver import json import configparser from conf import settings import os import hashlib STATUS_CODE = { 250: "Invalid cmd format,e.g:{'action':'get','filname':'test.py','size':344}", 251: "Incalid cmd", 252: "Invalid auth data", 253: "Wrong username or password", 254: "Passed authentication", 255: "Filename doesn't provided", 256: "Filename doesn't exist on the server", 257: "Ready to send file", 258: "md5 verification", 800: "The file exist,but not enough,is continue?", 801: "The file exist!", 802: "Ready to receive datas", 900: "md5 validate success" } class SeverHandler(socketserver.BaseRequestHandler): def handle(self): while 1: data = self.request.recv(1024).strip() data = json.loads(data.decode('utf-8')) if data.get("action"): if hasattr(self,data.get("action")): func = getattr(self,data.get("action")) func(**data) else: print('Invalid cmd') def send_response(self,state_code): response = {"status_code":state_code,'status_mes':STATUS_CODE[state_code]} self.request.sendall(json.dumps(response).encode('utf-8')) def auth(self,**data): username = data['username'] password = data['password'] user = self.authenticate(username,password) if user: self.send_response(254) else: self.send_response(253) def authenticate(self,user,pwd): config = configparser.ConfigParser() config.read(settings.ACCOUNT_PATH) if user in config.sections(): print("================================") if config[user]["Password"]==pwd: self.user = user self.mainPath = os.path.join(settings.BASE_DIR,"home",self.user) print("passed authentication") return self.user def put(self,**data): print("data: ",data) file_name = data.get('file_name') file_size = data.get('file_size') target_path = data.get('target_path') abs_path = os.path.join(self.mainPath,target_path,file_name) ##################### has_received = 0 if os.path.exists(abs_path): file_has_size = os.stat(abs_path).st_size if file_has_size<file_size: #断点续传 self.request.sendall("800".encode('utf-8')) choice = self.request.recv(1024).decode('utf-8') if choice=="Y": self.request.sendall(str(file_has_size).encode('utf-8')) has_received+=file_has_size f = open(abs_path,"ab") else: f = open(abs_path,'wb') else: #文件完全存在 self.request.sendall("801".encode('utf-8')) return else: self.request.sendall("802".encode('utf-8')) f = open(abs_path,"wb") md5_obj = hashlib.md5() while has_received<file_size: try: data = self.request.recv(1024) md5_obj.update(data) except Exception as e: break f.write(data) has_received+=len(data) md5_val = md5_obj.hexdigest() self.request.sendall(md5_val.encode('utf-8')) md5_client = self.request.recv(1024) print(md5_client) f.close() def ls(self,**data): file_list = os.listdir(self.mainPath) file_str = " ".join(file_list) if not len(file_list): file_str="<empty>" self.request.sendall(file_str.encode('utf-8')) def cd(self,**data): dirname = data.get("dirname") if dirname=="..": self.mainPath = os.path.dirname(self.mainPath) else: self.mainPath = os.path.join(self.mainPath,dirname) self.request.sendall(self.mainPath.encode('utf-8'))
到此为止,可以简单的完成上传任务,如果需要添加任务,只需要在ftp_client.py和server.py下面定义新的函数进行交互就可以了。