服务端
import socket,os,sys,json,struct,socketserver BASE_DIR=os.path.dirname(os.path.dirname(os.path.abspath(__file__))) SHARE_DIR=os.path.join(BASE_DIR,"share") TMP_DIR=os.path.join(BASE_DIR,"tmp") sys.path.append(BASE_DIR) from lib.md5sum import md5sum from lib.random_str import make_code class MyTcphandler(socketserver.BaseRequestHandler): def handle(self): conn = self.request print(conn) while True: #通信循环 try: data=conn.recv(1024) if not data: break params = json.loads(data.decode('utf-8')) # params=['get','a.txt'] cmd = params[0] # if hasattr(self, cmd) and len(params)>=2: func = getattr(self, cmd) func(params) else: conn.send("N".encode("utf-8")) print('\033[45mcmd not exists\033[0m') except Exception: break def get(self,params): #params=['get','a.txt'] filename=params[1] #filename='a.txt' filepath=os.path.join(SHARE_DIR,filename) # conn = self.request if os.path.exists(filepath): conn.send("Y".encode("utf-8")) #1、制作报头 headers = { 'filename': filename, "former_name":None, 'md5': md5sum(filepath), 'filesize': os.path.getsize(filepath), 'alias':make_code(16) } tmpfile=os.path.join(TMP_DIR,md5sum(filepath)) if os.path.exists(tmpfile): former_header=json.load(open(tmpfile,"r",encoding="utf-8")) headers["former_name"]=former_header["alias"] headers_json = json.dumps(headers) headers_bytes = headers_json.encode('utf-8') # 2、先发报头的长度 conn.send(struct.pack('i', len(headers_bytes))) # 3、发送报头 conn.send(headers_bytes) signal=conn.recv(3).decode('utf-8') if signal=="old": n_size = struct.unpack('i', conn.recv(4))[0] n_bytes = conn.recv(n_size) n_json = n_bytes.decode('utf-8') n=json.loads(n_json) with open(filepath,'rb') as f: f.seek(n) for line in f: conn.send(line) elif signal=="new": json.dump(headers,open(os.path.join(TMP_DIR,headers["md5"]),"w",encoding="utf-8")) #4、发送真实的数据 with open(filepath,'rb') as f: for line in f: conn.send(line) else: conn.send("N".encode("utf-8")) def put(self): pass if __name__ == '__main__': #取代链接循环 server=socketserver.ThreadingTCPServer(('127.0.0.1',8081),MyTcphandler) print('server starting...') server.serve_forever()
客户端
import socket,struct,json,os,sys BASE_DIR=os.path.dirname(os.path.dirname(os.path.abspath(__file__))) DOWNLOAD_DIR=os.path.join(BASE_DIR,"download") sys.path.append(BASE_DIR) from lib.md5sum import md5sum class FtpClient: def __init__(self,host,port): self.host=host self.port=port self.client=socket.socket(socket.AF_INET,socket.SOCK_STREAM) self.client.connect((self.host,self.port)) def interactive(self): while True: data=input('>>: ').strip() #get a.txt if not data:continue params=data.split() #parmas=['get','a.txt'] cmd=params[0] #cmd='get' if hasattr(self,cmd): func=getattr(self,cmd) func(params) #func(['get','a.txt']) def get(self,params): params_json=json.dumps(params) self.client.send(params_json.encode('utf-8')) status=self.client.recv(1).decode('utf-8') if status == "Y": # 1、先接收报头的长度 headers_size = struct.unpack('i', self.client.recv(4))[0] # 2、再收报头 headers_bytes = self.client.recv(headers_size) headers_json = headers_bytes.decode('utf-8') headers_dic = json.loads(headers_json) print('========>', headers_dic) filename = headers_dic['filename'] filesize = headers_dic['filesize'] alias= headers_dic['alias'] server_md5=headers_dic['md5'] former_name= headers_dic["former_name"] aliaspath=os.path.join(DOWNLOAD_DIR, alias) filepath = os.path.join(DOWNLOAD_DIR, filename) if former_name:former_path=os.path.join(DOWNLOAD_DIR, former_name) if former_name and os.path.exists(former_path): print ("*******有旧文件") self.client.send("old".encode('utf-8')) print("*******发出去了旧文件") recv_size=os.path.getsize(former_path) with open(former_path, 'ab') as f: f.seek(0,2) n=f.tell() n_json = json.dumps(n) n_bytes = n_json.encode('utf-8') self.client.send(struct.pack('i', len(n_bytes))) self.client.send(n_bytes) while recv_size < filesize: line = self.client.recv(1024) recv_size += len(line) f.write(line) if os.path.exists(filepath): overwrite(filepath, former_path, server_md5) else: os.rename(former_path,filepath) if md5sum(filepath) == server_md5: print ('===>下载成功') else: print ('===>下载失败') else: print("*******无旧文件") self.client.send("new".encode('utf-8')) print("*******发出去了") # 3、再收真实的数据 with open(aliaspath, 'wb') as f: recv_size = 0 while recv_size < filesize: line = self.client.recv(1024) recv_size += len(line) f.write(line) if os.path.exists(filepath): overwrite(filepath, aliaspath, server_md5) else: os.rename(aliaspath,filepath) if md5sum(filepath) == server_md5: print ('===>下载成功') else: print ('===>下载失败') else: print ("无此文件") def put(self): pass def overwrite(filepath,aliaspath,server_md5): while True: choice = input("文件已存在,是否覆盖(Y/N):") if choice == "Y": os.remove(filepath) os.rename(aliaspath, filepath) if md5sum(filepath) == server_md5: print('===>下载成功') else: print('===>下载失败') break elif choice == "N": nickname = input("重命名下载文件:") if not nickname: continue nickpath = os.path.join(DOWNLOAD_DIR, nickname) os.rename(aliaspath, nickpath) if md5sum(nickpath) == server_md5: print('===>下载成功') else: print('===>下载失败') break if __name__ == '__main__': client=FtpClient('127.0.0.1',8081) client.interactive()