Автор оригинала: Doug Hellmann.
Цель:
Обеспечить независимые платформы абстракции для ввода/вывода мультиплексирование на основе
Выбрать
модуль.
Модуль SELECTORS
обеспечивает независимую платформе, независимый от абстракции на верхней части функций мониторинга ввода-мониторинга, специфичной платформы в выборе.
Операционная модель
API в <Код> Селекторы на основе событий, аналогичны Poll () из Выбрать . Существует несколько реализаций, и модуль автоматически устанавливает псевдоним <код> defaultselector
для обозначения наиболее эффективной для конфигурации текущей системы.
Объект селектора предоставляет методы уточнения каких событий для поиска на розетке, а затем позволяет вызывающему звонору дождаться событий в зависимости от платформы. Регистрация заинтересованности в событии создает <код> SELETERKEY , который содержит розетку, информацию о событиях интереса, и необязательные данные приложения. Владелец селектора вызывает свой выбрать () , чтобы узнать о событиях. Возвращаемое значение – это последовательность ключевых объектов и растрата, указывающая, какие события произошли. Программа, использующая селектор, должна неоднократно звонить <код> Выберите () , затем обрабатывать события соответствующим образом.
Echo server.
Пример ECHO Server ниже использует данные приложения в Selectorkey для регистрации функции обратного вызова на новом событии. Основной цикл получает обратный вызов из ключа и проходит к нему сокет и маска событий. В качестве сервера запускается, он регистрирует функцию ACCECT () , который будет вызываться для чтения событий на главной сокетке сервера. Принятие соединения создает новую розетку, которое затем зарегистрировано с функцией Code> Read () в качестве обратного вызова для чтения событий.
selectors_echo_server.py
import selectors import socket mysel selectors.DefaultSelector() keep_running True def read(connection, mask): "Callback for read events" global keep_running client_address connection.getpeername() print('read({})'.format(client_address)) data connection.recv(1024) if data: # 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 def accept(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', 10000) 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) while keep_running: print('waiting for I/O') for key, mask in mysel.select(timeout1): callback key.data callback(key.fileobj, mask) print('shutting down') mysel.close()
Когда READ ()
нет никаких данных из сокета, он интерпретирует событие чтения как на другую сторону подключения соединения вместо отправки данных. Он удаляет розетку от селектора и закрывает его. Чтобы избежать бесконечного цикла, этот сервер также отключается после того, как он завершит связь с одним клиентом.
Echo Client.
Пример клиента ECHO ниже обрабатывает все события ввода/вывода в основном цикле, а не используя обратные вызовы. Он устанавливает селектор, чтобы сообщить о чтении событий на сокете и сообщать, когда сокет готов к отправке данных. Поскольку он смотрит на два типа событий, клиент должен проверить, что произошло, изучив значение маски. После того, как все его исходящие данные были отправлены, он изменяет конфигурацию селектора только для получения отчета, когда есть данные для чтения.
selectors_echo_client.py
import selectors import socket 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', 10000) 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, ) while keep_running: print('waiting for I/O') for key, mask in mysel.select(timeout1): connection key.fileobj client_address connection.getpeername() print('client({})'.format(client_address)) if mask & selectors.EVENT_READ: print(' ready to read') data connection.recv(1024) if data: # A readable client socket has data print(' received {!r}'.format(data)) bytes_received len(data) # Interpret empty result as closed connection, # and also close when we have received a copy # of all of the data sent. keep_running not ( data or (bytes_received and (bytes_received bytes_sent)) ) if mask & selectors.EVENT_WRITE: print(' ready to write') if not outgoing: # We are out of messages, so we no longer need to # write anything. Change our registration to let # us keep reading responses from the server. print(' switching to read-only') mysel.modify(sock, selectors.EVENT_READ) else: # Send the next message. next_msg outgoing.pop() print(' sending {!r}'.format(next_msg)) sock.sendall(next_msg) bytes_sent len(next_msg) print('shutting down') mysel.unregister(connection) connection.close() mysel.close()
Клиент отслеживает количество данных, которое он отправил, и сумма, которую она получила. Когда эти значения совпадают и ненулены, клиент выходит из цикла обработки и чисто отключается, удаляя розетку от селектора и закрывающую как разъем, так и селектор.
Сервер и клиент вместе
Клиент и сервер должны работать в отдельных клеммных окнах, поэтому они могут общаться друг с другом. Вывод сервера показывает входящее соединение и данные, а также ответ, отправляемый обратно клиенту.
$ python3 source/selectors/selectors_echo_server.py starting up on localhost port 10000 waiting for I/O waiting for I/O accept(('127.0.0.1', 59850)) waiting for I/O read(('127.0.0.1', 59850)) received b'This is the message. It will be repeated.' waiting for I/O read(('127.0.0.1', 59850)) closing shutting down
Вывод клиента показывает исходящее сообщение и ответ с сервера.
$ python3 source/selectors/selectors_echo_client.py connecting to localhost port 10000 waiting for I/O client(('127.0.0.1', 10000)) ready to write sending b'This is the message. ' waiting for I/O client(('127.0.0.1', 10000)) ready to write sending b'It will be repeated.' waiting for I/O client(('127.0.0.1', 10000)) ready to write switching to read-only waiting for I/O client(('127.0.0.1', 10000)) ready to read received b'This is the message. It will be repeated.' shutting down
Смотрите также
- Стандартная библиотечная документация для селекторов
- Выберите – apis нижнего уровня для обработки ввода/вывода.