FTP作业代码

服务端

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('33[45mcmd not exists33[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()
原文地址:https://www.cnblogs.com/shangdelu/p/8408658.html