Selector registration associates a resource, such as a socket, with a selector and identifies the events to monitor. Read and write events let an event loop wait for activity instead of repeatedly checking every socket. section 3.4
Registration works with two related selector operations:
- Register a server socket for read events so incoming client connections become notifications. section 3.4
- Register each accepted client socket for read events so incoming data can be processed. section 3.4
- Deregister sockets when they are no longer of interest; call select to wait for registered activity, optionally with a timeout. section 3.4
Non-blocking echo server
A server creates a non-blocking socket, registers it with DefaultSelector for EVENT_READ, and waits with select(timeout=1). When a client connects, the new connection is registered for data notifications; received data is written back to that client. 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)
Inspect the complete selector loop, including registration, event waiting, connection handling, and client processing. section 3.4
