The selectors
module in Python provides a high-level I/O multiplexing interface built on top of the lower-level select
module primitives (select
, poll
, epoll
, and kqueue
). This module allows you to manage multiple I/O events in a more efficient and portable way.
Table of Contents
- Introduction
- Key Classes and Methods
DefaultSelector
EVENT_READ
EVENT_WRITE
register
unregister
select
- Examples
- Basic Usage of
selectors
- Creating a Simple Server
- Handling Multiple Connections
- Real-World Use Case: Chat Server
- Basic Usage of
- Conclusion
- References
Introduction
The selectors
module provides a unified interface for monitoring multiple I/O events, making it easier to write portable and efficient I/O code. It abstracts the platform-specific details and allows you to work with a common interface for handling I/O readiness.
Key Classes and Methods
DefaultSelector
Creates a default selector object which automatically selects the most efficient implementation available on the platform (epoll
on Linux, kqueue
on BSD, select
on Windows, etc.).
import selectors
sel = selectors.DefaultSelector()
EVENT_READ
Constant to indicate that the file object is ready for reading.
selectors.EVENT_READ
EVENT_WRITE
Constant to indicate that the file object is ready for writing.
selectors.EVENT_WRITE
register
Registers a file object for monitoring.
sel.register(fileobj, selectors.EVENT_READ | selectors.EVENT_WRITE, data)
unregister
Unregisters a file object from monitoring.
sel.unregister(fileobj)
select
Monitors registered file objects and returns a list of ready file objects.
events = sel.select(timeout)
Examples
Basic Usage of selectors
import selectors
import socket
sel = selectors.DefaultSelector()
def accept(sock):
conn, addr = sock.accept()
print(f'Accepted connection from {addr}')
conn.setblocking(False)
sel.register(conn, selectors.EVENT_READ, read)
def read(conn):
data = conn.recv(1024)
if data:
print(f'Received data: {data}')
conn.send(data) # Echo back the data
else:
print('Closing connection')
sel.unregister(conn)
conn.close()
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.bind(('localhost', 12345))
sock.listen()
sock.setblocking(False)
sel.register(sock, selectors.EVENT_READ, accept)
while True:
events = sel.select()
for key, mask in events:
callback = key.data
callback(key.fileobj)
Creating a Simple Server
import selectors
import socket
sel = selectors.DefaultSelector()
def accept(sock, mask):
conn, addr = sock.accept()
print(f'Accepted connection from {addr}')
conn.setblocking(False)
sel.register(conn, selectors.EVENT_READ, read)
def read(conn, mask):
data = conn.recv(1024)
if data:
print(f'Received data: {data}')
conn.send(data)
else:
print('Closing connection')
sel.unregister(conn)
conn.close()
sock = socket.socket()
sock.bind(('localhost', 12345))
sock.listen(100)
sock.setblocking(False)
sel.register(sock, selectors.EVENT_READ, accept)
while True:
events = sel.select()
for key, mask in events:
callback = key.data
callback(key.fileobj, mask)
Handling Multiple Connections
import selectors
import socket
sel = selectors.DefaultSelector()
def accept(sock, mask):
conn, addr = sock.accept()
print(f'Accepted connection from {addr}')
conn.setblocking(False)
sel.register(conn, selectors.EVENT_READ, read)
def read(conn, mask):
data = conn.recv(1024)
if data:
print(f'Received data: {data}')
conn.send(data)
else:
print('Closing connection')
sel.unregister(conn)
conn.close()
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.bind(('localhost', 12345))
sock.listen()
sock.setblocking(False)
sel.register(sock, selectors.EVENT_READ, accept)
while True:
events = sel.select()
for key, mask in events:
callback = key.data
callback(key.fileobj, mask)
Real-World Use Case: Chat Server
import selectors
import socket
sel = selectors.DefaultSelector()
clients = {}
def accept(sock, mask):
conn, addr = sock.accept()
print(f'Accepted connection from {addr}')
conn.setblocking(False)
sel.register(conn, selectors.EVENT_READ, read)
clients[conn] = addr
def read(conn, mask):
data = conn.recv(1024)
if data:
print(f'Received data from {clients[conn]}: {data.decode()}')
broadcast(data, conn)
else:
print(f'Closing connection to {clients[conn]}')
sel.unregister(conn)
conn.close()
del clients[conn]
def broadcast(message, sender):
for conn in clients:
if conn != sender:
conn.send(message)
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.bind(('localhost', 12345))
sock.listen()
sock.setblocking(False)
sel.register(sock, selectors.EVENT_READ, accept)
print('Chat server started on port 12345')
while True:
events = sel.select()
for key, mask in events:
callback = key.data
callback(key.fileobj, mask)
Conclusion
The selectors
module in Python provides a high-level interface for efficient I/O multiplexing, making it easier to write portable and efficient network code. By abstracting the platform-specific details, it allows you to focus on building your application without worrying about the underlying system calls.
Comments
Post a Comment
Leave Comment