Главная страница
Навигация по странице:

  • См. также Описание модулей socket (стр. 586), select (стр. 572), SocketServer (стр. 611), пакета http (стр. 623).Модуль select

  • Константа Описание

  • Дополнительные возможности модуля

  • Усложненный пример использования асинхронного ввода-вывода

  • справочник по Python. мм isbn 9785932861578 9 785932 861578


    Скачать 4.21 Mb.
    Названиемм isbn 9785932861578 9 785932 861578
    Анкорсправочник по Python
    Дата08.05.2022
    Размер4.21 Mb.
    Формат файлаpdf
    Имя файлаBizli_Python-Podrobnyy-spravochnik.440222.pdf
    ТипСправочник
    #518195
    страница50 из 82
    1   ...   46   47   48   49   50   51   52   53   ...   82
    d.accept()
    Принимает соединение. Возвращает кортеж (client, addr), где в поле cli-
    ent
    возвращается объект сокета, используемый для обмена данными через соединение, а в поле addr – адрес клиента.
    d.bind(address)
    Присваивает сокету указанный адрес address. В аргументе address обычно передается кортеж (host, port), однако точное представление адреса зави- сит от используемого семейства адресов.
    d.close()
    Закрывает сокет.
    d.connect(address)
    Устанавливает соединение. В аргументе address передается кортеж (host,
    port)

    570
    Глава 21. Работа с сетью и сокеты
    d.create_socket(family, type)
    Создает новый сокет. Аргументы имеют тот же смысл, что и в функции socket.socket()
    d.listen([backlog])
    Принимает входящие соединения. В аргументе backlog передается целое число, которое передается функции socket.listen(), на основе которой реа- лизован этот метод.
    d.recv(size)
    Принимает до size байтов. Пустая строка служит признаком того, что кли- байтов. Пустая строка служит признаком того, что кли-
    . Пустая строка служит признаком того, что кли-
    Пустая строка служит признаком того, что кли- ент закрыл канал.
    d.send(data)
    Отправляет данные data. В аргументе data передается строка байтов.
    Следующая функция используется для запуска цикла приема и обработки событий:
    loop([timeout [, use_poll [, map [, count]]]])
    Запускает бесконечный цикл опроса. Если в аргументе use_poll передается значение False, опрос выполняется с помощью функции select(), в против- ном случае используется функция poll(). Аргумент timeout определяет пре- дельное время ожидания и по умолчанию принимает значение 30 секунд.
    В аргументе map передается словарь со всеми каналами для мониторинга.
    Аргумент count определяет количество операций опроса, которые должны быть выполнены перед тем, как функция вернет управление. Если в аргу- менте count передать None (по умолчанию), функция loop() выполняет беско- нечный цикл опроса, пока все каналы не будут закрыты. Если в аргументе
    count
    передать 1, функция выполнит одну проверку на наличие событий и вернет управление.
    Пример
    Следующий пример реализует веб-сервер с минимальными возможностя- ми на основе модуля asyncore. В примере определяются два класса: asynhttp, принимающий соединения, и asynclient, обрабатывающий запросы кли- ентов. Сравните этот пример с примером, который приводился в разде- ле с описанием модуля asynchat. Основное отличие этого примера состоит в том, что он реализован на более низком уровне, из-за чего потребовалось побеспокоиться о таких проблемах, как разбиение потока входных данных на строки, буферизация данных и идентификация пустых строк, заверша- ющих заголовки запросов.
    # Асинхронный сервер HTTP
    import asyncore, socket import os import mimetypes import collections try:
    from http.client import responses # Python 3

    Модуль asyncore
    571
    except ImportError:
    from httplib import responses # Python 2
    ёё
    # Следующий класс просто принимает входящие соединения class async_http(asyncore.dispatcher):
    def __init__(self,port):
    asyncore.dispatcher.__init__(self)
    self.create_socket(socket.AF_INET,socket.SOCK_STREAM)
    self.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    self.bind((‘’,port))
    self.listen(5)
    ёё
    def handle_accept(self):
    client,addr = self.accept()
    return async_http_handler(client)
    ёё
    # Класс, обслуживающий клиентов class async_http_handler(asyncore.dispatcher):
    def __init__(self, sock = None):
    asyncore.dispatcher.__init__(self,sock)
    self.got_request = False # Запрос HTTP прочитан?
    self.request_data = b””
    self.write_queue = collections.deque()
    self.responding = False
    ёё
    # Может использоваться для чтения, только если запрос еще не был прочитан def readable(self):
    return not self.got_request
    ёё
    # Читает входящие данные запроса def handle_read(self):
    chunk = self.recv(8192)
    self.request_data += chunk if b’\r\n\r\n’ in self.request_data:
    self.handle_request()
    ёё
    # Обрабатывает входящий запрос def handle_request(self):
    self.got_request = True header_data = self.request_data[:self.request_data.find(b’\r\n\r\n’)]
    header_text = header_data.decode(‘latin-1’)
    header_lines = header_text.splitlines()
    request = header_lines[0].split()
    op = request[0]
    url = request[1][1:]
    self.process_request(op,url)
    ёё
    # Обрабатывает запрос def process_request(self,op,url):
    self.responding = True if op == “GET”:
    if not os.path.exists(url):
    self.send_error(404,”File %s not found\r\n” % url)
    else:
    type, encoding = mimetypes.guess_type(url)

    572
    Глава 21. Работа с сетью и сокеты size = os.path.getsize(url)
    self.push_text(‘HTTP/1.0 200 OK\r\n’)
    self.push_text(‘Content-length: %d\r\n’ % size)
    self.push_text(‘Content-type: %s\r\n’ % type)
    self.push_text(‘\r\n’)
    self.push(open(url,”rb”).read())
    else:
    self.send_error(501,”%s method not implemented” % self.op)
    ёё
    # Обработка ошибок def send_error(self,code,message):
    self.push_text(‘HTTP/1.0 %s %s\r\n’ % (code, responses[code]))
    self.push_text(‘Content-type: text/plain\r\n’)
    self.push_text(‘\r\n’)
    self.push_text(message)
    ёё
    # Добавляет двоичные данные в выходную очередь def push(self,data):
    self.write_queue.append(data)
    ёё
    # Добавляет текстовые данные в выходную очередь def push_text(self,text):
    self.push(text.encode(‘latin-1’))
    ёё
    # Готов для записи, только если ответ готов def writable(self):
    return self.responding and self.write_queue
    ёё
    # Записывает данные ответа def handle_write(self):
    chunk = self.write_queue.popleft()
    bytes_sent = self.send(chunk)
    if bytes_sent != len(chunk):
    self.write_queue.appendleft(chunk[bytes_sent:])
    if not self.write_queue:
    self.close()
    ёё
    # Создать сервер a = async_http(8080)
    # Запустить бесконечный цикл опроса asyncore.loop()
    См. также
    Описание модулей socket (стр. 586), select (стр. 572), SocketServer (стр. 611), пакета http (стр. 623).
    Модуль select
    М
    одуль select предоставляет доступ к системным вызовам select() и poll().
    Системный вызов select() обычно используется для реализации опроса, или мультиплексирования, обработки нескольких потоков ввода-вывода, без использования потоков управления или дочерних процессов. В систе- мах UNIX эти вызовы можно использовать для работы с файлами, сокета-
    UNIX эти вызовы можно использовать для работы с файлами, сокета- эти вызовы можно использовать для работы с файлами, сокета-

    Модуль select
    573
    ми, каналами и со многими другими типами файлов. В Windows их можно использовать только для работы с сокетами.
    select(iwtd, owtd, ewtd [, timeout])
    Запрашивает информацию о готовности к вводу, выводу и о наличии ис- ключений для группы дескрипторов файлов. В первых трех аргументах передаются списки с целочисленными дескрипторами файлов или с объ- ектами, обладающими методом fileno(), который возвращает дескриптор файла. Аргумент iwtd определяет список объектов, которые проверяются на готовность к вводу, owtd – список объектов, которые проверяются на готовность к выводу, и ewtd – список объектов, которые проверяются на наличие исключительных ситуаций. В любом из аргументов допускается передавать пустой список. В аргументе timeout передается число с плаваю- щей точкой, определяющее предельное время ожидания в секундах. При вызове без аргумента timeout функция ожидает, пока хотя бы один из де- скрипторов не окажется в требуемом состоянии. Если в этом аргументе пе- редать число 0, функция просто выполнит опрос и тут же вернет управле- ние. Возвращает кортеж списков с объектами, находящимися в требуемом состоянии. Эти списки включают подмножества объектов в первых трех аргументах. Если к моменту истечения предельного времени ожидания ни один из дескрипторов не находится в требуемом состоянии, возвращается три пустых списка. В случае ошибки возбуждается исключение select.er-
    .er- er- ror
    . В качестве значения исключения возвращается та же информация, что и в исключениях IOError и OSError.
    poll()
    Создает объект, выполняющий опрос с помощью системного вызова poll().
    Эта функция доступна только в системах, поддерживающих системный вызов poll().
    Объект p, возвращаемый функцией poll(), поддерживает следующие мето- ды:
    p.register(fd [, eventmask])
    Регистрирует новый дескриптор файла fd. В аргументе fd может переда- ваться целочисленный дескриптор или объект, обладающий методом file- no()
    , с помощью которого можно получить дескриптор. В аргументе event-
    mask
    передается битная маска, составленная с помощью битовой операции
    ИЛИ из следующих флагов, которая определяет интересующие события:
    Константа
    Описание
    POLLIN
    Имеются данные, доступные для чтения.
    POLLPRI
    Имеются срочные данные, доступные для чтения.
    POLLOUT
    Готов к записи.
    POLLERR
    Ошибка.
    POLLHUP
    Разрыв соединения.
    POLLNVAL
    Недопустимый запрос.

    574
    Глава 21. Работа с сетью и сокеты
    При вызове функции без аргумента eventmask проверяются события POLLIN,
    POLLPRI
    и POLLOUT.
    p.unregister(fd)
    Удаляет дескриптор файла fd из объекта, выполняющего опрос. Возбуж- дает исключение KeyError, если дескриптор не был зарегистрирован ранее.
    p.poll([timeout])
    Проверяет наступление событий для всех зарегистрированных дескрипто- ров. Необязательный аргумент timeout определяет предельное время ожи- дания в миллисекундах. Возвращает список кортежей (fd, event), где поле
    fd
    является дескриптором файла, а поле event – битной маской, определяю- щей события. Поля этой битовой маски соответствуют константам POLLIN,
    POLLOUT
    и так далее. Например, чтобы проверить наличие события POLLIN, достаточно просто проверить значение выражение event & POLLIN на нера- венство нулю. Если возвращается пустой список, это означает, что в тече- ние указанного времени ожидания не возникло ни одного события.
    Дополнительные возможности модуля
    Функции select() и poll(), объявленные в этом модуле, совместимы со мно- гими операционными системами. Кроме того, в системах Linux модуль select предоставляет интерфейс к механизму определения состояния по перепаду и по значению (epoll), который может обеспечить значительно более высокую производительность. В системах BSD предоставляется воз- можность доступа к очереди ядра и к объектам событий. Описание этих программных интерфейсов можно найти в электронной документации к модулю select, по адресу http://docs.python.org/library/select.
    Усложненный пример использования
    асинхронного ввода-вывода
    Иногда модуль select используется для реализации серверов, основанных на тасклетах и сопрограммах – механизмах многозадачности, в которых не используются потоки управления или процессы. Следующий пример иллюстрирует данную концепцию, реализуя диспетчер задач для сопро- грамм, основанный на операциях ввода-вывода. Предупреждаю, что это самый сложный пример в книге и вам может потребоваться внимательно исследовать его, чтобы понять, как он работает. Возможно, вам также по- требуется ознакомиться с моим учебным руководством «A Curious Course on Coroutines and Concurrency» (http://www.dabeaz.com/coroutines), где можно найти дополнительный справочный материал.
    import select import types import collections
    ёё
    # Объект, представляющий запущенную задачу class Task(object):
    def __init__(self,target):
    self.target = target # Сопрограмма

    Модуль select
    575
    self.sendval = None # Значение, которое передается при возобновлении self.stack = [] # Стек вызовов
    ёё
    def run(self):
    try:
    result = self.target.send(self.sendval)
    if isinstance(result,SystemCall):
    return result if isinstance(result,types.GeneratorType):
    self.stack.append(self.target)
    self.sendval = None self.target = result else:
    if not self.stack: return self.sendval = result self.target = self.stack.pop()
    except StopIteration:
    if not self.stack: raise self.sendval = None self.target = self.stack.pop()
    ёё
    # Объект, представляющий “системный вызов”
    class SystemCall(object):
    def handle(self,sched,task):
    pass
    ёё
    # Объект диспетчера задач class Scheduler(object):
    def __init__(self):
    self.task_queue = collections.deque()
    self.read_waiting = {}
    self.write_waiting = {}
    self.numtasks = 0
    ёё
    # Создает новую задачу из сопрограммы def new(self,target):
    newtask = Task(target)
    self.schedule(newtask)
    self.numtasks += 1
    ёё
    # Добавляет задачу в очередь задач def schedule(self,task):
    self.task_queue.append(task)
    ёё
    # Приостанавливает задачу, пока дескриптор файла не станет
    # доступным для чтения def readwait(self,task,fd):
    self.read_waiting[fd] = task
    ёё
    # Приостанавливает задачу, пока дескриптор файла не станет
    # доступным для записи def writewait(self,task,fd):
    self.write_waiting[fd] = task
    ёё
    # Главный цикл диспетчера задач def mainloop(self,count=-1,timeout=None):

    576
    Глава 21. Работа с сетью и сокеты while self.numtasks:
    # Проверить наличие событий ввода-вывода if self.read_waiting or self.write_waiting:
    wait = 0 if self.task_queue else timeout r,w,e = select.select(self.read_waiting, self.write_waiting,
    [], wait)
    for fileno in r:
    self.schedule(self.read_waiting.pop(fileno))
    for fileno in w:
    self.schedule(self.write_waiting.pop(fileno))
    ёё
    # Запустить все задачи, имеющиеся в очереди,
    # которые готовы к запуску while self.task_queue:
    task = self.task_queue.popleft()
    try:
    result = task.run()
    if isinstance(result,SystemCall):
    result.handle(self,task)
    else:
    self.schedule(task)
    except StopIteration:
    self.numtasks -= 1
    ёё
    # Если нет задач, готовых для запуска,
    # требуется решить – продолжать или выйти else:
    if count > 0: count -= 1
    if count == 0:
    return
    ёё
    # Реализация различных системных вызовов class ReadWait(SystemCall):
    def __init__(self,f):
    self.f = f def handle(self,sched,task):
    fileno = self.f.fileno()
    sched.readwait(task,fileno)
    ёё
    class WriteWait(SystemCall):
    def __init__(self,f):
    self.f = f def handle(self,sched,task):
    fileno = self.f.fileno()
    sched.writewait(task,fileno)
    ёё
    class NewTask(SystemCall):
    def __init__(self,target):
    self.target = target def handle(self,sched,task):
    sched.new(self.target)
    sched.schedule(task)
    Программный код этого примера реализует «операционную систему» в ми- ниатюре. Ниже коротко описывается, как он действует:

    Модуль select
    577
    • Вся основная работа выполняется сопрограммами. Сопрограммы, как и генераторы, используют инструкцию yield, но в отличие от генерато- ров, в сопрограммах она используется не только чтобы возвращать зна- чения, но и чтобы принимать значения, которые передаются с помощью метода send(value).
    • Класс Task представляет готовую к запуску задачу и является всего лишь тонкой оберткой вокруг сопрограммы. Объект task класса Task может выполнять единственную операцию – task.run(). Этот метод воз- обновляет выполнение задачи, которая продолжает работать, пока не встретит следующую инструкцию yield, после чего выполнение задачи приостанавливается. После запуска задачи атрибут task.sendval содер- жит значение, которое должно быть послано соответствующему выра- жению yield в задаче. Задачи продолжают выполняться, пока не будет встречена следующая инструкция yield. Значение, которое воспроиз- водится этой инструкцией, определяет, что будет происходить дальше внутри задачи:
    • Если возвращаемым значением является другая сопрограмма (type.
    GeneratorType
    ), это означает, что задача временно передает управле- ние другой сопрограмме. Атрибут stack объекта класса Task представ- ляет стек вызовов сопрограмм, в котором сохраняется прежняя со- программа. При следующем запуске задачи управление будет пере- дано новой сопрограмме.
    • Если возвращаемым значением является экземпляр класса System-
    Call
    , это означает, что задаче требуется, чтобы диспетчер выполнил некоторую операцию от своего имени (например, запустил бы новую задачу, приостановил бы выполнение задачи, пока не появится воз- можность выполнить операцию ввода-вывода, и так далее). Назначе- ние этого объекта описывается чуть ниже.
    • Если возвращается какое-либо другое значение, это может означать одно из двух: либо управление вернула сопрограмма, запущенная из задачи, либо управление вернула сама задача. Если стек вызовов не пуст, это означает, что произошел возврат из сопрограммы, за- пущенной из задачи, поэтому вызывающая задача выталкивается из стека вызовов, а возвращаемое значение сохраняется, чтобы его можно было передать вызывающей сопрограмме. Вызывающая со- программа получит это значение, когда будет запущена в следую- щий раз. Если стек вызовов пуст, возвращаемое значение просто уничтожается.
    • Исключение StopIteration означает, что сопрограмма завершила свою работу. Когда появляется это исключение, управление переда- работу. Когда появляется это исключение, управление переда- работу. Когда появляется это исключение, управление переда-
    . Когда появляется это исключение, управление переда-
    Когда появляется это исключение, управление переда- ется предыдущей сопрограмме, сохраненной в стеке вызовов (если таковая имеется), либо исключение будет передано диспетчеру и в этом случае оно будет интерпретироваться, как признак завершения работы сопрограммы.
    • Объект класса SystemCall представляет системный вызов. Когда работа- ющей задаче требуется сообщить диспетчеру, что он должен выполнить операцию от своего имени, она с помощью инструкции yield возвращает

    1   ...   46   47   48   49   50   51   52   53   ...   82


    написать администратору сайта