BaseSelector is the abstract interface behind Python selector implementations. It hides operating-system-specific event notification so socket event loops can remain portable. section 3.4
Its event-loop model rests on three operations:
- Register sockets with the events to monitor, such as read or write, and deregister them when monitoring is no longer needed. section 3.4
- Call select to block until sockets are ready, optionally supplying a timeout that returns no events when it expires. section 3.4
- Use DefaultSelector when the platform-specific implementation should be selected automatically. section 3.4
Listing 3.7 Using selectors to build a non-blocking server
import selectors
import socket
from selectors import SelectorKey
from typing import List, Tuple
selector = selectors.DefaultSelector()
server_socket = socket.socket()
server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
server_address = ('127.0.0.1', 8000)
server_socket.setblocking(False)
server_socket.bind(server_address)
server_socket.listen()
selector.register(server_socket, selectors.EVENT_READ)
while True:
events: List[Tuple[SelectorKey, int]] = selector.select(timeout=1) #1
if len(events) == 0: #2
print('No events, waiting a bit more!')
for event, _ in events:
event_socket = event.fileobj #3
if event_socket == server_socket: #4
connection, address = server_socket.accept()
connection.setblocking(False)
print(f"I got a connection from {address}")
selector.register(connection, selectors.EVENT_READ) #5
else:
data = event_socket.recv(1024) #6
print(f"I got some data: {data}")
event_socket.send(data)
A non-blocking echo server demonstrates registering the listening socket, handling client connections, waiting for readable sockets, and returning received data. section 3.4
