Python学习第41天(ftp习题实现day3)
今天完成了断点续传部分,即文件传输一半后断掉链接,重新继续发送的实现,以及进度条的实现,今天在测试的时候神兽configpraser模块的害,txt和cfg文件还是不一样啊,最终还是得抓紧看看configpraser模块的模式啊
先展示一下今天的主要两个部分,server端的主要逻辑区域server.py文件
import socketserver import json import configparser from conf import settings import os,sys STATUS_CODE = { 250 : "Invalid cmd format, e.g: {'action':'get','filename':'test.py','size':344}", 251 : "Invalid cmd ", 252 : "Invalid auth data", 253 : "Wrong username or password", 254 : "Passed authentication", 255 : "Filename doesn't provided", 256 : "File doesn't exist on 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 valdate success" } class ServerHandler(socketserver.BaseRequestHandler): def handle(self): while True: data = self.request.recv(1024).strip() data = json.loads(data.decode('utf-8')) ''' {'action' : 'auth' , 'username' : 'xiao', 'password' : 123 } ''' if data.get('action'): if hasattr(self,data.get('action')): func = getattr(self,data.get('action')) func(**data) else: print('func error') self.request.send('func error'.encode('utf-8')) else: print('Invalid cmd') self.request.send('Invalid cmd'.encode('utf-8')) def send_reponse(self , state_code): response = {'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_reponse(254) else: self.send_reponse(253) def authenticate(self,user,pwd): cfg = configparser.ConfigParser() cfg.read(settings.ACCOUNT_PATH) if user in cfg.sections(): if cfg[user]['password'] == pwd: self.user = user # 登录成功之后保存了用户的登录信息 self.mainPath = os.path.join(settings.BASE_DIR,'home',self.user) # print('passed authentication') # 表示登录成功 return 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: # 表示文件已存在,且比较完整,返回给客户端801的信息 self.request.sendall('801'.encode('utf-8')) return else: self.request.sendall('802'.encode('utf-8')) f = open(abs_path , 'wb') while has_received < file_size: try: data = self.request.recv(1024) except Exception as e: break f.write(data) has_received += len(data) f.close()
ftp_client端
import socket import optparse import configparser import json import os import sys STATUS_CODE = { 250 : "Invalid cmd format, e.g: {'action':'get','filename':'test.py','size':344}", 251 : "Invalid cmd ", 252 : "Invalid auth data", 253 : "Wrong username or password", 254 : "Passed authentication", 255 : "Filename doesn't provided", 256 : "File doesn't exist on 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 valdate success" } # tcp_client = socket.socket(socket.AF_INET,socket.SOCK_STREAM) # tcp_client.connect(('127.0.0.1',8080)) # tcp_client.send('ok'.encode('utf-8')) # 以上是easy模式下的 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 ): # 对port端口进行校验 server = options.server port = options.port # username = options.username # password = options.password if int(options.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))) print('已连接') def interractive(self): if self.authenticate(): print('==========begin to interactive==========') cmd_info = input('[%s]'%self.user).strip() #比如会输入 put 12.png images 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.png 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.sendall(json.dumps(data).encode('utf-8')) is_exist = self.sock.recv(1024).decode('utf-8') # 下面对接收到的信息进行处理(转入服务端的书写) has_sent = 0 if is_exist == '800': # 表示文件存在不完整,即断点续传问题 choice = input('文件已存在,但文件不完整(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': # 表示文件已经存在,不用上传,所以就跳出put方法,重新转入输入命令那一行 # 即 interractive 方法 print("the file exist") return else: pass # 下面表示文件不存在的情况,就直接开始上传了 f = open(local_path, "rb") f.seek(has_sent) while has_sent < file_size: data = f.read(1024) self.sock.sendall(data) has_sent += len(data) self.show_progress(has_sent, file_size) f.close() print("put success!") def show_progress(self,has,total): rate = float(has)/float(total) rate_num = int(100*rate) # if self.last != rate_num sys.stdout.write("%s%% %s\r"%(rate_num,"-"*rate_num)) def authenticate(self): if self.options.username is None or self.options.password is None: username = input('username>>>') password = input('password>>>') print('ok') return self.get_auth_result(username,password) else: return self.get_auth_reult(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.sendall((json.dumps(data)).encode('utf-8')) response = self.response() print('response是',response['status_code']) if response['status_code'] == 254: self.user = user print(STATUS_CODE[254]) return True else: print(STATUS_CODE['status_code']) ch = ClientHandler() ch.interractive()
其他部分是完全没有变化的,今天时间有点紧,趁着晚上看看configpraser模块
import configparser config=configparser.ConfigParser() config.read('a.cfg') #查看所有的标题 res=config.sections() #['section1', 'section2'] print(res) #查看标题section1下所有key=value的key options=config.options('section1') print(options) #['k1', 'k2', 'user', 'age', 'is_admin', 'salary'] #查看标题section1下所有key=value的(key,value)格式 item_list=config.items('section1') print(item_list) #[('k1', 'v1'), ('k2', 'v2'), ('user', 'egon'), ('age', '18'), ('is_admin', 'true'), ('salary', '31')] #查看标题section1下user的值=>字符串格式 val=config.get('section1','user') print(val) #egon #查看标题section1下age的值=>整数格式 val1=config.getint('section1','age') print(val1) #18 #查看标题section1下is_admin的值=>布尔值格式 val2=config.getboolean('section1','is_admin') print(val2) #True #查看标题section1下salary的值=>浮点型格式 val3=config.getfloat('section1','salary') print(val3) #31.0
没找到比较清晰的介绍,目前还是一锅粥
明天再看看之前的教学视频吧,然后再补充,今天暂时就这样