• Python学习第58天(selector版本的ftp习题实现)


      本来打算开始web前端的学习的,但是布置的习题还是应该做一下的,花了不少时间,貌似还有一个功能没有完成,但是重点已经有了,其实先来回顾一下昨天引入的这个selector模块吧,说说里面的重点。  

    import selectors
    import socket
    
    sel = selectors.DefaultSelector()
    
    def accept(sock, mask):
        conn, addr = sock.accept()  # Should be ready
        print('accepted', conn, 'from', addr)
        conn.setblocking(False)
        sel.register(conn, selectors.EVENT_READ, read)
    
    def read(conn, mask):
        data = conn.recv(1000)  # Should be ready
        if data:
            print('echoing', repr(data), 'to', conn)
            conn.send(data)  # Hope it won't block
        else:
            print('closing', conn)
            sel.unregister(conn)
            conn.close()
    
    sock = socket.socket()
    sock.bind(('localhost', 1234))
    sock.listen(100)
    sock.setblocking(False)
    sel.register(sock, selectors.EVENT_READ, accept)
    
    while True:
        events = sel.select()
        for key, mask in events:
            callback = key.data
            callback(key.fileobj, mask)

      这里应该注意的句式,就是

        sel = selectors.DefaultSelector()

        sel.register(sock, selectors.EVENT_READ, accept)

      这两句就是绑定了监测对象,sock发生变化时候,就会执行accept

       大致就是个这么个意思,监测的对象可以是events是个对象列表,不止一个会发生变化,所以要利用for循环遍历,保证每次都能将每个有变化的conn接收到信息

      然后后面的习题就是通过这个特性实现的

      sel.register(sock, selectors.EVENT_READ, accept)把sock加入了监测列表,accept函数又把conn加入了监测列表

      好了,知识会议的差不多了,上干货,干了三个小时的杰作:

      客户端:

    import socket
    import os,sys
    BASE_DIR = os.path.dirname(os.path.abs(__file__))
    
    class selectFtpClent:
    
        def __init__(self):
            self.args = sys.argv
            if len(self.args) > 1:
                self.port = (self.args[1],int(self.args[2]))
            else:
                self.port = ('127.0.0.1', 8080)
            self.creat_socket()
            self.command_fanout()
    
        def creat_socket(self):
            try:
                self.sk = socket.socket()
                self.sk.connect(self.port)
                print('连接FTP服务器成功')
            except Exception as e:
                print('error: ',e)
    
    
        def command_fanout(self):
            while True:
                cmd = input('输入命令>>>')
                if cmd == 'exit()':
                    break
                cmd,file = cmd.split()
                if hasattr(self, cmd):
                    func = getattr(self,cmd)
                    func(cmd,file)
                else:
                    print('命令错误')
    
    
        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)
                self.sk.send(bytes(fileInfo,encoding = 'utf-8'))
                recvStatus = self.sk.recv(1024)
                print('recvStatus: ', recvStatus)
    
                has_send = 0
                if str(recvStatus, encoding = ' utf-8') == 'OK':
                    with open(file, 'rb') as f:
                        while fileSize > has_send:
                            contant = f.read(1024)
                            recv_size = len(contant)
                            self.sk.send(contant)
                            has_send +=recv_size
                            s = str(int(has_send/fileSize)) + '%'
                            print('正在上传文件:'+ fileName + '已上传' + s)
                    print('%s文件上传完毕%'%fileName)
                else:
                    print('文件不存在')
    
        def get(self):
            pass
    
    if __name__ == '__main__':
        selectFtpClent()

      服务端:

    import os
    import time
    BASE_DIR = os.path.dirname(os.path.abspath(__file__))
    import socket
    import selectors
    
    class selectFtpServer:
    
        def __init__(self):
            self.dic = {}
            self.hasReceived = 0
            self.sel = selectors.DefaultSelector()
            self.creat_socket()
            self.handle()
    
        def creat_socket(self):
            server = socket.socket()
            server.bind(('127.0.0.1' , 8080))
            server.listen(5)
            server.setblocking(False)
            self.sel.register(server, selectors.EVENT_READ, self.accept)
            print('服务器已开启,等待用户连接......')
    
        def handle(self):
            while True:
                events = self.sel.select()
                for key,mask in events:
                    callback = key.data
                    callback(key.fileobj, mask)
    
        def accept(self,sock,mask):
    
            conn, addr = sock.accept()
            print('from %s %s connected'%addr)
            conn.setblocking(False)
            # 作为后面conn的标记,防止很多conn的一个标记,同时记录相关信息
            self.dic[conn] = {}
    
        def read(self,conn,mask):
            try:
                if not self.dic[conn]:
                    data = conn.recv(1024)
                    cmd,filename,filesize = str(data,encoding = 'utf-8').split('|')
                    self.dic = {conn : { 'cmd':cmd , 'filename':filename ,'filesize':int(filesize)} }
    
                    if cmd == 'put':
                        conn.send(bytes('OK',encoding = 'utf-8'))
    
                    if self.dic[conn]['cmd'] == 'get':
                        file = os.path.join(BASE_DIR, 'download', filename)
    
                        if os.path.exists(file):
                            fileSize = os.path.getsize(file)
                            send_info = '%s|%s'%('YES',fileSize)
                            conn.send(bytes(send_info,encoding = 'utf-8'))
                        else:
                            send_info = '%s|%s'%('NO',0)
                            conn.send(bytes(send_info, encoding='utf-8'))
    
                else:
                    if self.dic[conn].get('cmd',None):
                        cmd = self.dic[conn].get('cmd')
                        if hasattr(self,cmd):
                            func = getattr(self,cmd)
                            func(conn)
                        else:
                            print('error cmd!!!')
                            conn.close()
                    else:
                        print('error cmd')
                        conn.close()
            except Exception as e:
                print('error: ',e)
    
    
    
    
        def put(self,conn):
    
            file_name = self.dic[conn]['filename']
            file_size = self.dic[conn]['filesize']
            path = os.path.join(BASE_DIR,'upload',file_name)
            recv_data = conn.recv(1024)
            self.hasReceived += len(recv_data)
    
            with open(path,'ab') as f:
                f.write(recv_data)
            if file_size == self.hasReceived:
                if conn in self.dic.keys():
                    self.dic[conn] = {}
                print('%s上传完毕!!!'%file_name)
    
        def get(self,conn):
            pass
    
    if __name__ == '__main__':
        selectFtpServer()

      虽然get方面目前还是pass,但是这个都是简单模式,关键是搞定了多客户的同时传递,避免socketserver模块一次存在的一些弊端,比如多用户分别占用的问题

      嗯,明天就要开始web前端了,激动。。。

  • 相关阅读:
    【Java-Web】初始化加载Serlvet工程后-HttpServlet报错
    【GIS】Cesium GLTF
    【视频】ffmpeg mov mp4 m3u8 ts
    【GIS】ArcGIS Server密码
    【NodeJS】http-server.cmd
    【GIS】Cesium回到初始位置
    【GIS】postgres(postgis) --》nodejs+express --》geojson --》leaflet
    深入浅出数据仓库中SQL性能优化之Hive篇
    大数据时代的技术hive:hive介绍
    hive优化之------控制hive任务中的map数和reduce数
  • 原文地址:https://www.cnblogs.com/xiaoyaotx/p/12741611.html
Copyright © 2020-2023  润新知