selector多路复用_Python3标准库:selectors I/O多路复用抽象

1. selectors I/O多路复用抽象

selectors模块在select中平台特定的I/O监视函数之上提供了一个平台独立的抽象层。

1.1 操作模型

selectors中的API是基于事件的,与select中的poll()类似。它有多个实现,并且这个模块会自动设置别名DefaultSelector来指示对当前系统配置最为高效的一个实现。

选择器对象提供了一些方法,可以指定在一个套接字上查找哪些事件,然后以一种平台独立的方式让调用者等待事件。注册对事件的兴趣会创建一个SelectorKey,其中包含套接字、所注册事件的有关信息,可能还有可选的应用数据。选择器的所有者调用它的select()方法来了解事件。返回值是一个键对象序列和一个指示发生了哪些事件的位掩码。使用选择器的程序要反复调用select(),然后适当地处理事件。

1.2 回送服务器

这里给出的回送服务器例子使用了Selectorkey中的应用数据来注册发生新事件时要调用的一个回调函数。主循环从键得到这个回调,并把套接字和事件掩码传递给该回调。服务器启动时,其会注册当主服务器套接字上发生读事件时要调用的accept()函数。接受连接会产生一个新的套接字,然后注册read()函数作为读事件的一个回调。

importselectors

importsocket

mysel=selectors.DefaultSelector()

keep_running=True

defread(connection,mask):

"Callback for read events"

globalkeep_running

client_address=connection.getpeername()

print('read({})'.format(client_address))

data=connection.recv(1024)

ifdata:

#A readable client socket has data

print('received {!r}'.format(data))

connection.sendall(data)

else:

#Interpret empty result as closed connection

print('closing')

mysel.unregister(connection)

connection.close()

#Tell the main loop to stop

keep_running=False

defaccept(sock,mask):

"Callback for new connections"

new_connection,addr=sock.accept()

print('accept({})'.format(addr))

new_connection.setblocking(False)

mysel.register(new_connection,selectors.EVENT_READ,read)

server_address=('localhost',9999)

print('starting up on {} port {}'.format(*server_address))

server=socket.socket(socket.AF_INET,socket.SOCK_STREAM)

server.setblocking(False)

server.bind(server_address)

server.listen(5)

mysel.register(server,selectors.EVENT_READ,accept)

whilekeep_running:

print('waiting for I/O')

forkey,maskinmysel.select(timeout=1):

callback=key.data

callback(key.fileobj,mask)

print('shutting down')

mysel.close()

如果read()没有从套接字接收到任何数据,那么当连接的另一端关闭时,它会中断读事件而不是发送数据。之后,会从选择器删除这个套接字,并将其关闭。由于这只是一个示例程序,所以这个服务器与唯一的客户结束通信后还会关闭服务器自身。

1.3 回送客户

下面的回送客户例子会处理主循环中的所有I/O事件,而不是使用回调。它会建立选择器来报告套接字上的读事件,并报告套接字什么时候准备好可以发送数据。由于它查看两种类型的事件,所以客户必须通过查看掩码值来检查发生了哪个事件。所有数据都发出后,它会修改选择器配置,只在有可读取的数据时才会报告。

importselectors

importsocket

mysel=selectors.DefaultSelector()

keep_running=True

outgoing=[

b'It will be repeated.',

b'This is the message.',

]

bytes_sent=0

bytes_received=0

#Connecting is a blocking operation, so call setblocking()

#after it returns.

server_address=('localhost',9999)

print('connecting to {} port {}'.format(*server_address))

sock=socket.socket(socket.AF_INET,socket.SOCK_STREAM)

sock.connect(server_address)

sock.setblocking(False)

#Set up the selector to watch for when the socket is ready

#to send data as well as when there is data to read.

mysel.register(

sock,

selectors.EVENT_READ|selectors.EVENT_WRITE,

)

whilekeep_running:

print('waiting for I/O')

forkey,maskinmysel.select(timeout=1):

connection=key.fileobj

client_address=connection.getpeername()

print('client({})'.format(client_address))

ifmask&selectors.EVENT_READ:

print('

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值