VB.net 2010 视频教程 VB.net 2010 视频教程 python基础视频教程
SQL Server 2008 视频教程 c#入门经典教程 Visual Basic从门到精通视频教程
当前位置:
首页 > Python基础教程 >
  • 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()函数作为读事件的一个回调。


  1. import selectors
  2. import socket
  3.  
  4. mysel = selectors.DefaultSelector()
  5. keep_running = True
  6.  
  7. def read(connection, mask):
  8. "Callback for read events"
  9. global keep_running
  10.  
  11. client_address = connection.getpeername()
  12. print('read({})'.format(client_address))
  13. data = connection.recv(1024)
  14. if data:
  15. # A readable client socket has data
  16. print(' received {!r}'.format(data))
  17. connection.sendall(data)
  18. else:
  19. # Interpret empty result as closed connection
  20. print(' closing')
  21. mysel.unregister(connection)
  22. connection.close()
  23. # Tell the main loop to stop
  24. keep_running = False
  25.  
  26. def accept(sock, mask):
  27. "Callback for new connections"
  28. new_connection, addr = sock.accept()
  29. print('accept({})'.format(addr))
  30. new_connection.setblocking(False)
  31. mysel.register(new_connection, selectors.EVENT_READ, read)
  32.  
  33. server_address = ('localhost', 9999)
  34. print('starting up on {} port {}'.format(*server_address))
  35. server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  36. server.setblocking(False)
  37. server.bind(server_address)
  38. server.listen(5)
  39.  
  40. mysel.register(server, selectors.EVENT_READ, accept)
  41.  
  42. while keep_running:
  43. print('waiting for I/O')
  44. for key, mask in mysel.select(timeout=1):
  45. callback = key.data
  46. callback(key.fileobj, mask)
  47.  
  48. print('shutting down')
  49. mysel.close()

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

1.3 回送客户

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


  1. import selectors
  2. import socket
  3.  
  4. mysel = selectors.DefaultSelector()
  5. keep_running = True
  6. outgoing = [
  7. b'It will be repeated.',
  8. b'This is the message. ',
  9. ]
  10. bytes_sent = 0
  11. bytes_received = 0
  12.  
  13. # Connecting is a blocking operation, so call setblocking()
  14. # after it returns.
  15. server_address = ('localhost', 9999)
  16. print('connecting to {} port {}'.format(*server_address))
  17. sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  18. sock.connect(server_address)
  19. sock.setblocking(False)
  20.  
  21. # Set up the selector to watch for when the socket is ready
  22. # to send data as well as when there is data to read.
  23. mysel.register(
  24. sock,
  25. selectors.EVENT_READ | selectors.EVENT_WRITE,
  26. )
  27.  
  28. while keep_running:
  29. print('waiting for I/O')
  30. for key, mask in mysel.select(timeout=1):
  31. connection = key.fileobj
  32. client_address = connection.getpeername()
  33. print('client({})'.format(client_address))
  34.  
  35. if mask & selectors.EVENT_READ:
  36. print('