python selectors模块实现 IO多路复用机制的上传下载
程序员文章站
2023-01-22 20:29:56
import selectorsimport socketimport os,timeBASE_DIR = os.path.dirname(os.path.abspath(__file__))class Server: # sel = selectors.DefaultSelector() def ... ......
import selectors import socket import os,time base_dir = os.path.dirname(os.path.abspath(__file__)) class server: # sel = selectors.defaultselector() def __init__(self): self.ip_port=('127.0.0.1',8080) self.sel=selectors.defaultselector()
#根据平台选择最佳的io多路机制,比如linux就会选择epoll self.dic = {} self.create_sock() self.handle() def create_sock(self): sock = socket.socket() sock.bind(('localhost', 1234)) sock.listen(100) # sock.setblocking(false)
#注册监听对象,绑定accept self.sel.register(sock, selectors.event_read, self.accept def handle(self): while true:
#sel监听sock变化,当sock实例化时,赋值给events,通过回调函数触发
#key.data(key.fileobj,mask) accept(sock,mask),
#当有客户端连接时通过accept注册到read……
events = self.sel.select() # [sock,conn1,conn2] for key, mask in events: callback = key.data # sel accept sel read callback(key.fileobj, mask) #accept(sock,mask),read(conn1,mask)……
def accept(self,sock, mask): print('登录服务端---') conn, addr = sock.accept() # should be ready print('accepted', conn, 'from', addr) # conn.setblocking(false) self.sel.register(conn, selectors.event_read, self.read)
self.dic[conn]={} def read(self,conn, mask): try: if not self.dic[conn]: data = conn.recv(1024) try: cmd, filename, filesize = str(data.decode("utf-8")).split("|") self.dic[conn] = {"cmd": cmd, "filename": filename, "filesize": filesize, "hasreceived": 0} except exception as e: cmd, filename = str(data.decode("utf-8")).split("|") self.dic[conn] = {"cmd": cmd, "filename": filename,"filesize": os.path.getsize(os.path.join(base_dir, "load", filename)),"hassended": 0} if cmd=='put':#上传 conn.send('ok'.encode('utf8')) if cmd=='get':#下载 conn.send(str(self.dic[conn]['filesize']).encode('utf8')) else: if self.dic[conn].get('cmd',none): cmd =self.dic[conn].get('cmd') if hasattr(self,cmd): func=getattr(self,cmd) func(conn,mask)#反射命令分发 else: print('error') except exception as e: print(e,conn,'断开连接') conn.close() self.sel.unregister(conn) def put(self,conn,mask): filename=self.dic[conn]['filename'] filesize = self.dic[conn]['filesize'] path = os.path.join(base_dir, "upload", filename) data = conn.recv(1024) conn.send("success".encode("utf-8")) self.dic[conn]['hasreceived'] += len(data) with open(path, "ab") as f: f.write(data) if self.dic[conn]['hasreceived'] == self.dic[conn]['filesize']: self.dic[conn] = {} print("上传结束") #少写一步 def get(self, conn, mask): filename = self.dic[conn]['filename'] path = os.path.join(base_dir, "load", filename) with open(path, "rb") as f: f.seek(self.dic[conn]["hassended"], 0) data = f.read(1024) conn.send(data) self.dic[conn]['hassended'] += len(data) if self.dic[conn]['hassended'] == self.dic[conn]["filesize"]: self.dic[conn] = {} print("下载结束") time.sleep(0.5) if __name__ == "__main__": server()
import os, time, sys base_dir = os.path.dirname(os.path.abspath(__file__)) import socket import selectors class selectftpclient: def __init__(self): self.port = ("127.0.0.1", 8001) self.create_socket() self.command_fanout() def create_socket(self): try: self.sock = socket.socket() self.sock.connect(self.port) print("连接ftp成功!") except exception: print("连接失败!") 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('调用错误!') # 上传 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.sock.send(bytes(fileinfo, encoding="utf-8")) recvstatus = self.sock.recv(1024) hassend = 0 if str(recvstatus, encoding="utf-8") == 'ok': with open(file, "rb") as f: while filesize > hassend: contant = f.read(10) recv_size = len(contant) self.sock.send(contant) hassend += recv_size s = str(int(hassend / filesize * 100)) + "%" print("正在上传文件:" + filename + " 已经上传: " + s) time.sleep(0.5) print("%s文件上传完毕" % (filename,)) else: print("文件不存在") # 下载 def get(self, cmd, file): fileinfo = "%s|%s" % (cmd, file) self.sock.send(bytes(fileinfo, encoding="utf-8")) filesize = int(self.sock.recv(10).decode("utf-8")) f = open(file, "ab") i = 0 while i < filesize: self.sock.send("ok".encode("utf-8")) data = self.sock.recv(10) f.write(data) i += len(data) s = str(int(i / filesize * 100)) + "%" print("正在上传文件:" + file + " 已经下载: " + s) print("下载完成") f.close() if __name__ == "__main__": selectftpclient()