python IO多路复用 selectors
import selectors,socket,threading
selector=selectors.DefaultSelector()
def accept(socket:socket.socket):
conn,client=socket.accept()
print('accept new conn: {}'.format(conn))
conn.setblocking(False)
selector.register(conn,selectors.EVENT_READ,data=recv)
def recv(conn:socket.socket):
data=conn.recv(1024)
print(data)
#注册selector中监听的对象,事件和回调data(函数)
sock=socket.socket(family=socket.AF_INET,type=socket.SOCK_STREAM)
ip='127.0.0.1'
port=9999
sock.bind((ip,port))
sock.listen()
sock.setblocking(False)
e=threading.Event()
# 监控sock,可读时调用accept函数
key=selector.register(sock,selectors.EVENT_READ,accept)
print(key)
while not e.is_set():
events=selector.select() # select阻塞
if events: # events为二元列表
print('event:',events)
for key,mask in events: # 对象key(fileobj,fd,events,data)
print('key,mask:',key,mask)
callback=key.data
callback(key.fileobj)
import selectors,socket,threading
selector=selectors.DefaultSelector()
def accept(socket:socket.socket,mask):
conn,client=socket.accept()
print('accept new conn: {}'.format(conn))
conn.setblocking(False)
selector.register(conn,selectors.EVENT_READ | selectors.EVENT_WRITE,data=recv)
def recv(conn:socket.socket,mask):
data=conn.recv(1024)
print(data)
sock=socket.socket(family=socket.AF_INET,type=socket.SOCK_STREAM)
ip='127.0.0.1'
port=9999
sock.bind((ip,port))
sock.listen()
sock.setblocking(False)
#注册selector中监听的对象,事件和回调data(函数)
key=selector.register(sock,selectors.EVENT_READ,accept)
print(key)
e=threading.Event()
def work(event:threading.Event):
while not event.is_set():
events=selector.select()
if events:
print('events = {}'.format(events))
for key,mask in events:
print('key = {}'.format(key))
print('mask = {}'.format(mask))
callback=key.data
callback(key.fileobj,mask)
try:
threading.Thread(target=work,name='work thread',args=(e,)).start()
except OSError as e:
print(e.errno,e.filename,e.filename2,e.strerror)
while not e.is_set():
cmd=input('>>').strip()
if cmd == 'quit':
e.set()
fobjs=[]
print(selector.get_map().items())
for fobj,key in selector.get_map().items(): # 注册的文件对象fd和key的映射
print(fobj,key)
print(key.fileobj)
key.fileobj.close()
fobjs.append(fobj)
for v in fobjs:
print('unregister {}'.format(v))
selector.unregister(v)
selector.close()
import threading,selectors,socket,datetime,sys
class Server:
def __init__(self,ip='127.0.0.1',port=9999):
self.addr=(ip,port)
self.sock=socket.socket(family=socket.AF_INET,type=socket.SOCK_STREAM)
self.event=threading.Event()
self.selector=selectors.DefaultSelector()
self.clients={}
def start(self):
self.sock.bind(self.addr)
self.sock.listen()
self.sock.setblocking(False)
self.selector.register(self.sock,selectors.EVENT_READ,data=self.__accept)
threading.Thread(target=self.__run,name='run selector',daemon=True).start()
def __run(self):
while not self.event.is_set():
events=self.selector.select(1)
for key,mask in events:
callback=key.data
callback(key.fileobj,mask)
def __accept(self,sock:socket.socket,mask):
conn,client=sock.accept()
self.clients[client]=conn
conn.setblocking(False)
self.selector.register(conn,selectors.EVENT_READ,self.__recv)
def __recv(self,conn:socket.socket,mask):
#ConnectionAbortedError: [WinError 10053] An established connection was aborted by the software in your host machine
#client主动断开时,server会抛异常
try:
data=conn.recv(1024).decode().strip()
except ConnectionAbortedError as e:
print(e.errno,e.filename,e.filename2,e.strerror)
sys.exit(0)
msg='{:%Y-%m-%d %H:%M:%S} {}:{} {}'.format(datetime.datetime.now(),*conn.getpeername(),data)
print(msg)
for key in self.selector.get_map().values():
if key.data == self.__recv: # 移除self.__accept
key.fileobj.send(msg.encode())
def stop(self):
self.event.set()
fd_list=[]
for fd,key in self.selector.get_map().items():
key.fileobj.close()
fd_list.append(fd)
for b in fd_list:
self.selector.unregister(b)
self.selector.close()
def main():
vc=Server()
vc.start()
e=threading.Event()
while not e.wait(2):
cmd=input('>>').strip()
if cmd == 'quit':
vc.stop()
e.wait(1)
break
if __name__ == '__main__':
main()
import threading,selectors,socket,datetime,sys,queue
class Conn:
def __init__(self,conn:socket.socket,handle):
self.conn=conn
self.queue=queue.Queue()
self.handle=handle
class Server:
def __init__(self,ip='',port=9999):
self.addr=(ip,port)
self.sock=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
self.clients={}
self.selector=selectors.DefaultSelector()
self.event=threading.Event()
def start(self):
self.sock.bind(self.addr)
self.sock.listen()
self.sock.setblocking(False)
self.selector.register(self.sock,selectors.EVENT_READ,self.__accept)
threading.Thread(target=self.__run,name='run selector',daemon=True).start()
def __run(self):
while not self.event.is_set():
events=self.selector.select(1)
for key,mask in events:
if callable(key.data):
callback=key.data
else:
callback=key.data.handle
callback(key.fileobj,mask)
def __accept(self,sock:socket.socket,mask):
conn,client=sock.accept()
self.clients[client]=Conn(conn,self.__handle)
conn.setblocking(False)
self.selector.register(conn,selectors.EVENT_READ | selectors.EVENT_WRITE,self.clients[client])
def __handle(self,conn:socket.socket,mask):
if (mask & selectors.EVENT_READ) == selectors.EVENT_READ:
data=conn.recv(1024).decode().strip()
msg='{:%Y/%m/%d %H:%M:%S} {}:{} {}'.format(datetime.datetime.now(),*conn.getpeername(),data)
print(msg)
for c in self.clients.values():
c.queue.put(msg.encode())
if (mask & selectors.EVENT_WRITE) == selectors.EVENT_WRITE:
remote=conn.getpeername()
client=self.clients[remote]
while not client.queue.empty():
conn.send(client.queue.get())
def stop(self):
self.event.set()
fd_list=[]
for fd,key in self.selector.get_map():
key.fileobj.close()
fd_list.append(fd)
for b in fd_list:
self.selector.unregister(b)
self.selector.close()
def main():
e=threading.Event()
s=Server()
s.start()
while not e.is_set():
cmd=input('>>').strip()
if cmd == 'quit':
s.stop()
e.wait(2)
break
if __name__ == "__main__":
main()
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律