基于python3的socket文件传输和校验

来源:互联网 发布:如何给给淘宝号升级 编辑:程序博客网 时间:2024/06/09 22:09

基于socket的 文件传输并进行MD5值校验

文件传输分为两个类,一个是服务端,一个是客户端。

客户端发起发送文件或接收文件的请求,服务端收到请求后接收或发送文件,最后进行MD5值的校验

socket数据通过struct模块打包

需要发送文件到服务端时,调用sendFile函数,struct包内包含文件信息、文件大小、文件MD5等信息,服务端接收到文件后进行MD5值校验,校验成功后则返回成功

需要从服务器下载文件时,调用recvFile函数,收到文件后进行MD5校验

client类代码如下

import socketimport struct,osimport subprocessdataFormat='8s32s100s100sl'class fileClient():    def __init__(self,addr):        self.addr = addr        self.action = ''        self.fileName = ''        self.md5sum = ''        self.clientfilePath = ''        self.serverfilePath = ''        self.size = 0    def struct_pack(self):        ret = struct.pack(dataFormat,self.action.encode(),self.md5sum.encode(),self.clientfilePath.encode(),                          self.serverfilePath.encode(),self.size)        return ret    def struct_unpack(self,package):        self.action,self.md5sum,self.clientfilePath,self.serverfilePath,self.size = struct.unpack(dataFormat,package)        self.action = self.action.decode().strip('\x00')        self.md5sum = self.md5sum.decode().strip('\x00')        self.clientfilePath = self.clientfilePath.decode().strip('\x00')        self.serverfilePath = self.serverfilePath.decode().strip('\x00')    def sendFile(self,clientfile,serverfile):        if not os.path.exists(clientfile):            print('源文件/文件夹不存在')            return "No such file or directory"        self.action = 'upload'        (status, output) = subprocess.getstatusoutput("md5sum " + clientfile + " | awk '{printf $1}'")        if status == 0:            self.md5sum = output        else:            return "md5sum error:"+status        self.size = os.stat(clientfile).st_size        self.serverfilePath = serverfile        self.clientfilePath = clientfile        ret = self.struct_pack()        s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)        try:            s.connect(self.addr)            s.send(ret)            recv = s.recv(1024)            if recv.decode() == 'dirNotExist':                print("目标文件/文件夹不存在")                return "No such file or directory"            elif recv.decode() == 'ok':                fo = open(clientfile, 'rb')                while True:                    filedata = fo.read(1024)                    if not filedata:                        break                    s.send(filedata)                fo.close()                recv = s.recv(1024)                if recv.decode() == 'ok':                    print("文件传输成功")                    s.close()                    return 0                else:                    s.close()                    return "md5sum error:md5sum is not correct!"        except Exception as e:            print(e)            return "error:"+str(e)    def recvFile(self,clientfile,serverfile):        if not os.path.isdir(clientfile):            filePath,fileName = os.path.split(clientfile)        else:            filePath = clientfile        if not os.path.exists(filePath):            print('本地目标文件/文件夹不存在')            return "No such file or directory"        self.action = 'download'        self.clientfilePath = clientfile        self.serverfilePath = serverfile        s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)        try:            s.connect(self.addr)            ret = self.struct_pack()            s.send(ret)            recv = s.recv(struct.calcsize(dataFormat))            self.struct_unpack(recv)            if self.action.startswith("ok"):                if os.path.isdir(clientfile):                    fileName = (os.path.split(serverfile))[1]                    clientfile = os.path.join(clientfile, fileName)                self.recvd_size = 0                file = open(clientfile, 'wb')                while not self.recvd_size == self.size:                    if self.size - self.recvd_size > 1024:                        rdata = s.recv(1024)                        self.recvd_size += len(rdata)                    else:                        rdata = s.recv(self.size - self.recvd_size)                        self.recvd_size = self.size                    file.write(rdata)                file.close()                print('\n等待校验...')                (status, output) = subprocess.getstatusoutput("md5sum " + clientfile + " | awk '{printf $1}'")                if output == self.md5sum:                    print("文件传输成功")                else:                    print("文件校验不通过")                    (status, output) = subprocess.getstatusoutput("rm " + clientfile)            elif self.action.startswith("nofile"):                print('远程源文件/文件夹不存在')                return "No such file or directory"        except Exception as e:            print(e)            return "error:"+str(e)
server类代码如下
import socketimport struct,osimport subprocessimport socketserverdataFormat='8s32s100s100sl'class fileServer(socketserver.StreamRequestHandler):    def struct_pack(self):        ret = struct.pack(dataFormat, self.action.encode(), self.md5sum.encode(), self.clientfilePath.encode(),                          self.serverfilePath.encode(), self.size)        return ret    def struct_unpack(self, package):        self.action, self.md5sum, self.clientfilePath, self.serverfilePath, self.size = struct.unpack(dataFormat,                                                                                                      package)        self.action = self.action.decode().strip('\x00')        self.md5sum = self.md5sum.decode().strip('\x00')        self.clientfilePath = self.clientfilePath.decode().strip('\x00')        self.serverfilePath = self.serverfilePath.decode().strip('\x00')    def handle(self):        print('connected from:', self.client_address)        fileinfo_size = struct.calcsize(dataFormat)        self.buf = self.request.recv(fileinfo_size)        if self.buf:            self.struct_unpack(self.buf)            print("get action:"+self.action)            if self.action.startswith("upload"):                try:                    if os.path.isdir(self.serverfilePath):                        fileName = (os.path.split(self.clientfilePath))[1]                        self.serverfilePath = os.path.join(self.serverfilePath, fileName)                    filePath,fileName = os.path.split(self.serverfilePath)                    if not os.path.exists(filePath):                        self.request.send(str.encode('dirNotExist'))                    else:                        self.request.send(str.encode('ok'))                        recvd_size = 0                        file = open(self.serverfilePath, 'wb')                        while not recvd_size == self.size:                            if self.size - recvd_size > 1024:                                rdata = self.request.recv(1024)                                recvd_size += len(rdata)                            else:                                rdata = self.request.recv(self.size - recvd_size)                                recvd_size = self.size                            file.write(rdata)                        file.close()                        (status, output) = subprocess.getstatusoutput("md5sum " + self.serverfilePath + " | awk '{printf $1}'")                        if output == self.md5sum:                            self.request.send(str.encode('ok'))                        else:                            self.request.send(str.encode('md5sum error'))                except Exception as e:                    print(e)                finally:                    self.request.close()            elif self.action.startswith("download"):                try:                    if os.path.exists(self.serverfilePath):                        (status, output) = subprocess.getstatusoutput("md5sum " + self.serverfilePath + " | awk '{printf $1}'")                        if status == 0:                            self.md5sum = output                        self.action = 'ok'                        self.size = os.stat(self.serverfilePath).st_size                        ret = self.struct_pack()                        self.request.send(ret)                        fo = open(self.serverfilePath, 'rb')                        while True:                            filedata = fo.read(1024)                            if not filedata:                                break                            self.request.send(filedata)                        fo.close()                    else:                        self.action = 'nofile'                        ret = self.struct_pack()                        self.request.send(ret)                except Exception as e:                    print(e)                finally:                    self.request.close()

调用server,并开启服务
import fileSocketimport threadingimport socketserverimport timeserverIp = '127.0.0.1'serverPort = 19821serverAddr = (serverIp,serverPort)class fileServerth(threading.Thread):    def __init__(self):        threading.Thread.__init__(self)        self.create_time = time.time()        self.local = threading.local()    def run(self):        print("fileServer is running...")        fileserver.serve_forever()fileserver = socketserver.ThreadingTCPServer(serverAddr, fileSocket.fileServer)fileserverth = fileServerth()fileserverth.start()

调用client,发送/接受文件

import fileSocketserverIp = '127.0.0.1'serverPort = 19821serverAddr = (serverIp,serverPort)fileclient = fileSocket.fileClient(serverAddr)fileclient.sendFile('fromClientPath/file','toServerPath/file')fileclient.recvFile('toClientPath/file','fromServerPath/file')