zoukankan      html  css  js  c++  java
  • python-selctors实现文件上传

    服务端代码:程序目录server/server.py   上传文件目录:server/upload

    import os
    import time
    import socket
    import selectors                     #封装了一些相应的操作
    
    BASE_DIR=os.path.dirname(os.path.abspath(__file__))
    
    #第二步:
    class selectFtpServer:
        def __init__(self):
            self.dic = {}                            #创建空字典
            self.hasReceived=0
            self.sel = selectors.DefaultSelector()   #通过selectors模块下的DefaultSelector这个类拿I/O多路方法拿到实例对象变成实例变量self.sel
            self.create_socket()                     #create_socket()是创建socket对象函数完成绑定功能
            self.handle()                            #handle()函数完成循环监听
    
        #create_socket函数是用来创建socket对象完成绑定功能
        def create_socket(self):
            server = socket.socket()                                      #创建socket对象赋值server
            server.bind(('192.168.1.160', 8080))                        #绑定
            server.listen(5)                                              #监听
            server.setblocking(False)                                    #设置非阻塞
            self.sel.register(server, selectors.EVENT_READ,self.accept)   #有了server对象通过self.sel实例变量register注册完成绑定功能(server跟self.accept做绑定)
            print("服务端已启动,等待客户端连接.....")
    
        #handle()函数完成循环监听
        def handle(self):
            while True:                        #第一步:程序启动后走while循环                                       #第七步:运行完accept函数后到这里
                #所有操作围绕一个对象self.sel实例变量核心对象展开的
                events = self.sel.select()       #第二步:调用self.sel实例变量,监听的内容server封装到events对象里    #第八步:如果客户端发过来此刻监听的内容就有变化有俩个对象server和conn封装到events对象里
                for key, mask in events:        #第三步:for循环events(可迭代对象)拿到key和mask                      #第九步:for循环events(可迭代对象)拿到key和mask
                    callback = key.data          #第四步:当前key.data是self.accept函数赋值给callback                 #第十步:当前key.data是read函数赋值给callback
                    #key.fileobj是拿到的监听的对象。
                    callback(key.fileobj, mask)  #第五步:运行callback执行accpt()函数                                 #第十一步:运行callback执行read()函数里面放到的之前链接相应的文件描述符conn
                    #print('当前监听的对象:', key.fileobj)
    
        #第六步:accept函数接收连接服务端的客户端信息
        def accept(self,sock,mask):                                   #接收sock和mask
            conn, addr = sock.accept()                                 #sock.accept接收此时链接服务端的socket对象拿到conn和addr
            #print('accepted', conn, 'from', addr)
            print("from %s %s connected" %addr)
            conn.setblocking(False)                                   #设置成非阻塞
            self.sel.register(conn, selectors.EVENT_READ, self.read)   #把conn跟read做绑定后程序返回到handle()函数里的events继续监听
            #print(conn)
    
            self.dic[conn] = {}                                        #在空字典里进行了conn赋值,self.dic={conn:{},}
    
        #第十二步:read函数返回给客户端ok
        def read(self,conn, mask):                                                  #接收了conn和mask
            try:                                                                    #加异常防止客户端突然断开
                if not self.dic[conn]:                                              #判断self.dic[conn]里面是否是空字典,如果是空字典,代表第一次进来
                    data = conn.recv(1024)                                           #conn接收了客户端发来的数据
                    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继续监听
    
                    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):
                            fileSize = os.path.getsize(file)
                            send_info = '%s|%s' %('YES',fileSize)
                            conn.send(bytes(send_info, encoding='utf8'))
                        else:
                            send_info = '%s|%s' %('NO',0)
                            conn.send(bytes(send_info, encoding='utf8'))
    
                else:                                                #如果不是空字典代表不是第一次进来
                    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']
            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] = {}
                print("%s 上传完毕!" %fileName)
    
    if __name__=='__main__':
        selectFtpServer()              #第一步:实例化触发selectFtpServer这个类

    客户端代码:目录结果:/client/clenb.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=("192.168.1.160",8080)               #如果没有第二个参数默认取这个
            self.create_socket()                             #
            self.command_fanout()                            #进行命令分发
    
        #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:
                cmd = input('>>>').strip()   #引导用户输入上传还是下载
                if cmd == 'exit()':
                    break
                cmd,file = cmd.split()        #把输入的命令分开进行反射
                if hasattr(self,cmd):
                    func = getattr(self,cmd)
                    func(cmd,file)
                else:
                    print('调用错误!')
    
        #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,file):
            pass
    
    if __name__=='__main__':
        selectFtpClient()
  • 相关阅读:
    C++11 新特性之 序列for循环
    有一种acm题目叫做,奇葩!
    00103_死锁、Lock接口、等待唤醒机制
    Oracle物化视图梳理
    16 Managing Undo
    [.NET开发] C#编程调用Cards.dll实现图形化发牌功能示例
    [.NET开发] C#连接MySQL的两个简单代码示例
    [.NET开发] C#实现发送手机验证码功能
    [.NET开发] C#实现剪切板功能
    [.NET开发] C#实现的SQL备份与还原功能示例
  • 原文地址:https://www.cnblogs.com/xixi18/p/10082509.html
Copyright © 2011-2022 走看看