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()
  • 相关阅读:
    我的WCF之旅(1):创建一个简单的WCF程序
    与众不同 windows phone (15) Media(媒体)之后台播放音频
    与众不同 windows phone (14) Media(媒体)之音频播放器, 视频播放器, 与 Windows Phone 的音乐和视频中心集成
    与众不同 windows phone (10) Push Notification(推送通知)之推送 Tile 通知, 推送自定义信息
    与众不同 windows phone (17) Graphic and Animation(画图和动画)
    与众不同 windows phone (5) Chooser(选择器)
    与众不同 windows phone (26) Contacts and Calendar(联系人和日历)
    与众不同 windows phone (7) Local Database(本地数据库)
    与众不同 windows phone (19) Device(设备)之陀螺仪传感器, Motion API
    与众不同 windows phone (16) Media(媒体)之编辑图片, 保存图片到相册, 与图片的上下文菜单“应用程序...”和“共享...”关联, 与 Windows Phone 的图片中心集成
  • 原文地址:https://www.cnblogs.com/xixi18/p/10082509.html
Copyright © 2011-2022 走看看