zoukankan      html  css  js  c++  java
  • Python3代码-selctors实现文件上传与下载

    server.py

    import selectors
    import socket
    import os
    import time
    
    
    BASE_DIR =os.path.abspath(os.path.dirname(__file__))
    
    class selectFtpserver:
        def __init__(self):
            self.dic = {}  # 创建空字典
            self.hasReceived = 0
            self.hasSend=0
            self.sel = selectors.DefaultSelector()  # 生成一个select对象
            self.create_socket() #create_socket()是创建socket对象函数完成绑定功能
            self.hanle()  #handle()函数完成循环监听
    
        def create_socket(self):
            sock = socket.socket()
            sock.bind(('127.0.0.1', 8899))
            sock.listen()
            sock.setblocking(False)
            self.sel.register(sock, selectors.EVENT_READ, self.accept)  # 把刚生成的sock连接对象注册到select连接列表中,并交给accept函数处理
            print("服务端已打开,请连接客户端")
    
        def hanle(self):
            while True:
                events = self.sel.select()  # 默认是阻塞,有活动连接就返回活动的连接列表
                # 这里看起来是select,其实有可能会使用epoll,如果你的系统支持epoll,那么默认就是epoll
                # print("event==",events)
                for key, mask in events:
                    callback = key.data  # 去调accept函数
                    callback(key.fileobj, mask)  # key.fileobj就是readable中的一个socket连接对象
    
        def accept(self,sock, mask):
            conn, addr = sock.accept()  # Should be ready
            print('accepted', conn, 'from', addr)
            conn.setblocking(False)  # 设定非阻塞
            self.sel.register(conn, selectors.EVENT_READ, self.read)  # 新连接注册read回调函数
            self.dic[conn] = {}  # 在空字典里进行了conn赋值,self.dic={conn:{},}
    
        def read(self, conn, mask):  # 接收了conn和mask
            try:  # 加异常防止客户端突然断开
                if not self.dic[conn]:  # 判断self.dic[conn]里面是否是空字典,如果是空字典,代表第一次进来
                    print('====第一次进来')
                    data = conn.recv(1024)  # conn接收了客户端发来的数据
                    print("data==",str(data, encoding='utf-8'))
                    cmd, filename,filesize = str(data, encoding='utf-8').split('|')  # 把接收到客户端发来的包解开拿到cmd,filename,filesize个信息
                    self.dic = {conn: {"cmd": cmd, "filename": filename, "filesize": int(filesize)}}  # 把拿到的cmd,filename,filesize信息放到self.dic字典里去后程序返回到handle()函数里的events继续监听
                    print(self.dic)
                    if cmd == 'put':  # 如果接收的信息是put
                        conn.send(bytes("OK", encoding='utf8'))  # 给客户端返回一条数据
                    if self.dic[conn]['cmd'] == 'get':
                        file = os.path.join(BASE_DIR, "upload", filename)
    
                        if os.path.exists(file):
                            print("文件存在的情况,返回YES给客户端")
                            filesize = os.path.getsize(file)
                            self.dic[conn]['filesize'] = filesize
                            print("self.dic",self.dic)
                            send_info = '%s|%s' % ('YES', filesize)
                            conn.send(bytes(send_info, encoding='utf8'))
                        else:
                            print("文件不存在情况下")
                            send_info = '%s|%s' % ('NO', 0)
                            conn.send(bytes(send_info, encoding='utf8'))
                            self.dic[conn] = {} #文件不存在的情况下,要将清空字典
                else:  # 如果不是空字典代表不是第一次进来
                    print('不是第一次来的')
                    print(self.dic)
                    if self.dic[conn].get('cmd', None):  # 对接收的命令进行分发判断是put还是get
                        cmd = self.dic[conn].get('cmd')
                        if hasattr(self, cmd):  # 如果cmd=put调用put函数,如果是cmd=get函数调用get函数
                            func = getattr(self, cmd)
                            func(conn)
                        else:
                            print("error cmd!")
                            conn.close()
                    else:
                        print("error cmd!")
                        conn.close()
            except Exception as e:
                print('断开的客户端信息是:', conn)
                self.sel.unregister(conn)  # 如果没有接收到数据做一个关闭解除
                conn.close()
    
            # put上传函数
        def put(self, conn):
            fileName = self.dic[conn]['filename']
            fileSize = self.dic[conn]['filesize']
            # print("BASE_DIR",BASE_DIR)
            path = os.path.join(BASE_DIR, "upload", fileName)  # 拿到要接收的信息
            # print(fileName,fileSize,path)
    
            recv_data = conn.recv(1024)  # 接收客户端上传的数据1024字节
            self.hasReceived += len(recv_data)  # 把接收的数据累加到变量self.hasReceived
    
            with open(path, 'ab') as f:  # 打开文件
                f.write(recv_data)  # 把接收的数据写到文件里去
    
            if fileSize == self.hasReceived:  # 判断文件大小跟接收大小是否一样
                if conn in self.dic.keys():  # 如果文件大小跟接收大小一样清空字典
                    self.dic[conn] = {}
                self.hasReceived = 0  #S上传结束之后,需要将self.hasReceived 重置成功
                print("%s 上传完毕!" % fileName)
    
        def get(self,conn):
            fileName = self.dic[conn]['filename']
            file = os.path.join(BASE_DIR, "upload", fileName)
            # fileSize = os.path.getsize(file)
            fileSize=self.dic[conn]['filesize']
    
            data = conn.recv(1024)  # conn接收了客户端发来的数据
            dataOK = str(data, encoding='utf-8')
    
            if dataOK == 'OK':
                with open(file, 'rb') as f:  # 打开文件
                    while fileSize > self.hasSend:  # 循环的发送文件给客户端
                        contant = f.read(1024)
                        recv_size = len(contant)
                        conn.send(contant)
                        self.hasSend += recv_size
                        s = str(int(self.hasSend / fileSize * 100)) + "%"
                        print("正在下载文件: " + fileName + " 已经下载:" + s)
    
                if fileSize == self.hasSend:  # 判断文件大小跟接收大小是否一样
                    if conn in self.dic.keys():  # 如果文件大小跟接收大小一样清空字典
                        self.dic[conn] = {}
                    print("%s 下载完毕!" % fileName)
                    self.hasSend = 0
    
    if __name__ == '__main__':
        selectFtpserver()

    client.py

    import socket
    import os,sys
    BASE_DIR=os.path.dirname(os.path.abspath(__file__))
    
    class selectFtpClient:
        def __init__(self):
            self.args=sys.argv                              #sys.argv在命令行输入的参数,第一个参数默认文件名,第二个参数跟IP地址和端口
            if len(self.args)>1:                            #如果大于1把第二个参数俩个值赋值给port
                self.port=(self.args[1],int(self.args[2]))
            else:
                self.port=("127.0.0.1",8899)               #如果没有第二个参数默认取这个
            self.create_socket()                             #
            self.command_fanout()                            #进行命令分发
            self.mainPath = os.path.join(BASE_DIR, 'filename')  # 获取该客户端下的filename路径
    
        #create_socket函数创建socket对象连接服务端
        def create_socket(self):
            try:
                self.sk = socket.socket()
                self.sk.connect(self.port)
                print('连接FTP服务器成功!')
            except Exception as e:
                print("eroor:",e)
    
        #command_fanout()函数进行命令分发
        def command_fanout(self):
            while True:
                try:
                    print("----------------welcome to ftp client-------------------")
                    self.help_info()
                    cmd_info = input('>>>请输入操作命令:').strip()  # put 12.png images
                    if not cmd_info:
                        continue
                    cmd,file = cmd_info.split()  ##按照空格分隔
                    # print("命令是什么", cmds)
                    if cmd == "quit":
                        break
                    if hasattr(self, cmd):
                        func = getattr(self, cmd)
                        func(cmd,file)
                        Tag = input("是否继续进入ftp clinet,请选择Y/N:").strip()
                        if Tag.upper() == 'Y':
                            continue
                        else:
                            break
                    else:
                        print('No such command ,please try again')
                except Exception as e:  # server关闭了
                    print('%s' % e)
                    break
    
        def help_info(self):
            print ('''
                  get + (文件名)    表示下载文件
                  put + (文件名)    表示上传文件
                  quit              表示退出登录
            ''')
    
        #put()上传函数
        def put(self,cmd,file):
            if os.path.isfile(file):                            #判断本地文件是否存在
                fileName = os.path.basename(file)                #取出文件的名字
                fileSize = os.path.getsize(file)                 #取出文件的大小
                fileInfo = '%s|%s|%s'%(cmd,fileName,fileSize)  #给文件名字大小打包成fileInf
                self.sk.send(bytes(fileInfo, encoding='utf8'))  #调用send方法把fileInf发给服务端
                recvStatus = self.sk.recv(1024)                  #接收服务端返回的OK内容
                print('recvStatus' , recvStatus)
                hasSend = 0
                if str(recvStatus, encoding='utf8') == "OK":   #如果接收到服务端返回的OK
                    with open(file, 'rb') as f:                #打开文件
                        while fileSize > hasSend :              #循环的去上传文件
                            contant = f.read(1024)
                            recv_size = len(contant)
                            self.sk.send(contant)
                            hasSend += recv_size
                            s=str(int(hasSend/fileSize*100))+"%"
                            print("正在上传文件: "+fileName+" 已经上传:" +s)
                    print('%s文件上传完毕' % (fileName,))
            else:
                print('要上传的文件不存在')
    
        #get()下载函数
        def get(self,cmd,fileName):
            path = os.path.join(BASE_DIR, "download", fileName)  # 拿到要接收的信息
            fileSize=0
            fileInfo = '%s|%s|%s' % (cmd, fileName, fileSize)  # 给文件名字大小打包成fileInf
            print(fileInfo)
            self.sk.send(bytes(fileInfo, encoding='utf8'))  # 调用send方法把fileInfo发给服务端
    
            recvdata = self.sk.recv(1024)  # 接收服务端返回的是否存在文件内容
            recvStatus, fileSize = str(recvdata, encoding='utf-8').split('|')
            print("recvStatus==",recvStatus,fileSize)
            fileSize = int(fileSize)
    
            hasReceived = 0
            if recvStatus == "YES":  # 如果接收到服务端返回的YES
                self.sk.send(bytes('OK', encoding='utf8'))  # 通知服务端可以正常下载了
    
                while fileSize > hasReceived:  # 循环的发送文件给客户端
                    recv_data = self.sk.recv(1024)  # 接收客户端上传的数据1024字节
                    hasReceived += len(recv_data)  # 把接收的数据累加到变量self.hasReceived
                    print("hasReceived",hasReceived)
    
                    with open(path, 'ab') as f:  # 打开文件
                        f.write(recv_data)  # 把接收的数据写到文件里去
    
                    if fileSize == hasReceived:  # 判断文件大小跟接收大小是否一样
                        print("%s 下载完毕!" % fileName)
                        recvStatus = 'YESS'
            else:
                 print('要下载的文件不存在')
    
    
    if __name__=='__main__':
        selectFtpClient()
  • 相关阅读:
    2018JAVA面试题附答案
    微服务概述
    Java后台开发面试题总结
    郁金香搜索引擎方案
    单点登录
    Redis为什么是单线程
    数据库原理-范式
    权限分配之一级菜单优化添加和编辑页面图标
    权限分配之一级菜单保留原搜索条件
    django分页的东西, 不详细, 但是也足够了。
  • 原文地址:https://www.cnblogs.com/sugh/p/13930873.html
Copyright © 2011-2022 走看看