Документация Python неофициальный перевод

asyncio-stream.md

370 строк · 19.8 КБ · обычная страница · сырой текст · скачать

1> **Источник:** https://python-all.ru/3.7/library/asyncio-stream.html2>3> «Документация Python на русском» – неофициальный перевод официальной документации Python: версии от 2.6 до 3.16, полнотекстовый поиск, английский оригинал рядом с переводом. Эта Markdown-версия страницы предназначена для работы с LLM: вставьте её в ChatGPT, Claude или Cursor.45---67# Потоки данных89Потоки данных – это высокоуровневые примитивы, готовые к использованию с async/await, для работы с сетевыми соединениями. Потоки данных позволяют отправлять и получать данные без использования колбэков или низкоуровневых протоколов и транспортов.1011Ниже приведён пример TCP-эхо-клиента, написанного с использованием asyncio потоков данных:1213```python14import asyncio1516async def tcp_echo_client(message):17    reader, writer = await asyncio.open_connection(18        '127.0.0.1', 8888)1920    print(f'Send: {message!r}')21    writer.write(message.encode())2223    data = await reader.read(100)24    print(f'Received: {data.decode()!r}')2526    print('Close the connection')27    writer.close()28    await writer.wait_closed()2930asyncio.run(tcp_echo_client('Hello World!'))31```3233Смотрите также раздел [Примеры](https://python-all.ru/3.7/library/asyncio-stream.html#examples) ниже.3435Функции потоков данных3637Следующие функции asyncio верхнего уровня можно использовать для создания и работы с потоками данных:3839#### `coroutine asyncio.open_connection(host=None, port=None, *, loop=None, limit=None, ssl=None, family=0, proto=0, flags=0, sock=None, local_addr=None, server_hostname=None, ssl_handshake_timeout=None)`4041Устанавливает сетевое соединение и возвращает пару объектов `(reader, writer)`.4243Возвращаемые объекты *reader* и *writer* являются экземплярами классов [`StreamReader`](https://python-all.ru/3.7/library/asyncio-stream.html#asyncio.StreamReader) и [`StreamWriter`](https://python-all.ru/3.7/library/asyncio-stream.html#asyncio.StreamWriter).4445Аргумент *loop* необязателен и всегда определяется автоматически при ожидании этой функции из корутины.4647Параметр *limit* определяет ограничение размера буфера, используемого возвращаемым экземпляром [`StreamReader`](https://python-all.ru/3.7/library/asyncio-stream.html#asyncio.StreamReader). По умолчанию *limit* установлен в 64 КиБ.4849Остальные аргументы передаются напрямую в [`loop.create_connection()`](https://python-all.ru/3.7/library/asyncio-eventloop.html#asyncio.loop.create_connection).5051Новое в версии 3.7: параметр *ssl\_handshake\_timeout*.5253#### `coroutine asyncio.start_server(client_connected_cb, host=None, port=None, *, loop=None, limit=None, family=socket.AF_UNSPEC, flags=socket.AI_PASSIVE, sock=None, backlog=100, ssl=None, reuse_address=None, reuse_port=None, ssl_handshake_timeout=None, start_serving=True)`5455Запускает сокет-сервер.5657Колбэк *client\_connected\_cb* вызывается при каждом установлении нового подключения клиента. Он получает пару `(reader, writer)` в качестве двух аргументов – экземпляры классов [`StreamReader`](https://python-all.ru/3.7/library/asyncio-stream.html#asyncio.StreamReader) и [`StreamWriter`](https://python-all.ru/3.7/library/asyncio-stream.html#asyncio.StreamWriter).5859*client\_connected\_cb* может быть обычным вызываемым объектом или [корутинной функцией](https://python-all.ru/3.7/library/asyncio-task.html#coroutine); если это корутинная функция, она будет автоматически запланирована как [`Task`](https://python-all.ru/3.7/library/asyncio-task.html#asyncio.Task).6061Аргумент *loop* необязателен и всегда определяется автоматически при ожидании этого метода из корутины.6263Параметр *limit* определяет ограничение размера буфера, используемого возвращаемым экземпляром [`StreamReader`](https://python-all.ru/3.7/library/asyncio-stream.html#asyncio.StreamReader). По умолчанию *limit* установлен в 64 КиБ.6465Остальные аргументы передаются напрямую в [`loop.create_server()`](https://python-all.ru/3.7/library/asyncio-eventloop.html#asyncio.loop.create_server).6667Новое в версии 3.7: параметры *ssl\_handshake\_timeout* и *start\_serving*.6869Unix-сокеты7071#### `coroutine asyncio.open_unix_connection(path=None, *, loop=None, limit=None, ssl=None, sock=None, server_hostname=None, ssl_handshake_timeout=None)`7273Устанавливает соединение через Unix-сокет и возвращает пару `(reader, writer)`.7475Аналогично [`open_connection()`](https://python-all.ru/3.7/library/asyncio-stream.html#asyncio.open_connection), но работает с Unix-сокетами.7677См. также документацию [`loop.create_unix_connection()`](https://python-all.ru/3.7/library/asyncio-eventloop.html#asyncio.loop.create_unix_connection).7879[Доступность](https://python-all.ru/3.7/library/intro.html#availability): Unix.8081Новое в версии 3.7: параметр *ssl\_handshake\_timeout*.8283Изменено в версии 3.7: Параметр *path* теперь может быть [объектом, подобным пути](https://python-all.ru/3.7/glossary.html#term-path-like-object)8485#### `coroutine asyncio.start_unix_server(client_connected_cb, path=None, *, loop=None, limit=None, sock=None, backlog=100, ssl=None, ssl_handshake_timeout=None, start_serving=True)`8687Запуск сервера Unix-сокетов.8889Аналогично [`start_server()`](https://python-all.ru/3.7/library/asyncio-stream.html#asyncio.start_server), но работает с Unix-сокетами.9091См. также документацию [`loop.create_unix_server()`](https://python-all.ru/3.7/library/asyncio-eventloop.html#asyncio.loop.create_unix_server).9293[Доступность](https://python-all.ru/3.7/library/intro.html#availability): Unix.9495Новое в версии 3.7: параметры *ssl\_handshake\_timeout* и *start\_serving*.9697Изменено в версии 3.7: Параметр *path* теперь может быть [path-подобным объектом](https://python-all.ru/3.7/glossary.html#term-path-like-object).9899---100101## StreamReader102103#### `class asyncio.StreamReader`104105Представляет объект чтения, предоставляющий API для чтения данных из потока ввода-вывода.106107Не рекомендуется создавать объекты *StreamReader* напрямую; вместо этого используйте [`open_connection()`](https://python-all.ru/3.7/library/asyncio-stream.html#asyncio.open_connection) и [`start_server()`](https://python-all.ru/3.7/library/asyncio-stream.html#asyncio.start_server).108109#### `coroutine read(n=-1)`110111Читает до *n* байт. Если *n* не указан или равен `-1`, читает до EOF и возвращает все прочитанные байты.112113Если получен EOF и внутренний буфер пуст, возвращает пустой объект `bytes`.114115#### `coroutine readline()`116117Читает одну строку, где «строка» – это последовательность байтов, заканчивающаяся `\n`.118119Если получен EOF и `\n` не найден, метод возвращает частично прочитанные данные.120121Если получен EOF и внутренний буфер пуст, возвращается пустой объект `bytes`.122123#### `coroutine readexactly(n)`124125Прочитать ровно *n* байт.126127Возбуждается [`IncompleteReadError`](https://python-all.ru/3.7/library/asyncio-exceptions.html#asyncio.IncompleteReadError), если EOF достигнут до того, как прочитано *n* байт. Используйте атрибут [`IncompleteReadError.partial`](https://python-all.ru/3.7/library/asyncio-exceptions.html#asyncio.IncompleteReadError.partial), чтобы получить частично прочитанные данные.128129#### `coroutine readuntil(separator=b'\n')`130131Читает данные из потока до тех пор, пока не будет найден *separator*.132133В случае успеха данные и разделитель удаляются из внутреннего буфера (потребляются). Возвращаемые данные включают разделитель в конце.134135Если объем прочитанных данных превышает настроенный лимит потока, возбуждается исключение [`LimitOverrunError`](https://python-all.ru/3.7/library/asyncio-exceptions.html#asyncio.LimitOverrunError), а данные остаются во внутреннем буфере и могут быть прочитаны снова.136137Если EOF достигнут до того, как найден полный разделитель, возбуждается исключение [`IncompleteReadError`](https://python-all.ru/3.7/library/asyncio-exceptions.html#asyncio.IncompleteReadError), и внутренний буфер сбрасывается. Атрибут [`IncompleteReadError.partial`](https://python-all.ru/3.7/library/asyncio-exceptions.html#asyncio.IncompleteReadError.partial) может содержать часть разделителя.138139Новое в версии 3.5.2.140141#### `at_eof()`142143Возвращает `True`, если буфер пуст и был вызван `feed_eof()`.144145## StreamWriter146147#### `class asyncio.StreamWriter`148149Представляет объект-писатель, предоставляющий API для записи данных в поток ввода-вывода.150151Не рекомендуется создавать объекты *StreamWriter* напрямую; вместо этого используйте [`open_connection()`](https://python-all.ru/3.7/library/asyncio-stream.html#asyncio.open_connection) и [`start_server()`](https://python-all.ru/3.7/library/asyncio-stream.html#asyncio.start_server).152153#### `can_write_eof()`154155Возвращает `True`, если нижележащий транспорт поддерживает метод [`write_eof()`](https://python-all.ru/3.7/library/asyncio-stream.html#asyncio.StreamWriter.write_eof), и `False` в противном случае.156157#### `write_eof()`158159Закрывает конец потока для записи после сброса буферизованных данных записи.160161#### `transport`162163Возвращает базовый транспорт asyncio.164165#### `get_extra_info(name, default=None)`166167Предоставляет доступ к дополнительной информации о транспорте; подробнее см. [`BaseTransport.get_extra_info()`](https://python-all.ru/3.7/library/asyncio-protocol.html#asyncio.BaseTransport.get_extra_info).168169#### `write(data)`170171Записывает *data* в поток.172173Этот метод не подчиняется управлению потоком. Вызовы `write()` должны сопровождаться вызовом [`drain()`](https://python-all.ru/3.7/library/asyncio-stream.html#asyncio.StreamWriter.drain).174175#### `writelines(data)`176177Записывает в поток список (или любой итерируемый объект) байтов.178179Этот метод не подчиняется управлению потоком. Вызовы `writelines()` должны сопровождаться вызовом [`drain()`](https://python-all.ru/3.7/library/asyncio-stream.html#asyncio.StreamWriter.drain).180181#### `coroutine drain()`182183Ожидает, когда можно будет возобновить запись в поток данных. Пример:184185```python186writer.write(data)187await writer.drain()188```189190Это метод управления потоком, который взаимодействует с базовым буфером записи ввода-вывода. Когда размер буфера достигает верхней границы, *drain()* блокируется, пока размер буфера не уменьшится до нижней границы, после чего запись можно возобновить. Если ждать нечего, [`drain()`](https://python-all.ru/3.7/library/asyncio-stream.html#asyncio.StreamWriter.drain) возвращает управление немедленно.191192#### `close()`193194Закрывает поток.195196#### `is_closing()`197198Возвращает `True`, если поток данных закрыт или находится в процессе закрытия.199200Добавлено в версии 3.7.201202#### `coroutine wait_closed()`203204Ожидает закрытия потока данных.205206Должен вызываться после [`close()`](https://python-all.ru/3.7/library/asyncio-stream.html#asyncio.StreamWriter.close), чтобы дождаться закрытия нижележащего соединения.207208Добавлено в версии 3.7.209210## Примеры211212### TCP-эхо-клиент с использованием потоков данных213214TCP-эхо-клиент с использованием функции [`asyncio.open_connection()`](https://python-all.ru/3.7/library/asyncio-stream.html#asyncio.open_connection):215216```python217import asyncio218219async def tcp_echo_client(message):220    reader, writer = await asyncio.open_connection(221        '127.0.0.1', 8888)222223    print(f'Send: {message!r}')224    writer.write(message.encode())225226    data = await reader.read(100)227    print(f'Received: {data.decode()!r}')228229    print('Close the connection')230    writer.close()231232asyncio.run(tcp_echo_client('Hello World!'))233```234235> **См. также**236>237> Пример [протокол TCP-эхо-клиента](https://python-all.ru/3.7/library/asyncio-protocol.html#asyncio-example-tcp-echo-client-protocol) использует низкоуровневый метод [`loop.create_connection()`](https://python-all.ru/3.7/library/asyncio-eventloop.html#asyncio.loop.create_connection).238239### TCP-эхо-сервер с использованием потоков данных240241TCP-эхо-сервер с использованием функции [`asyncio.start_server()`](https://python-all.ru/3.7/library/asyncio-stream.html#asyncio.start_server):242243```python244import asyncio245246async def handle_echo(reader, writer):247    data = await reader.read(100)248    message = data.decode()249    addr = writer.get_extra_info('peername')250251    print(f"Received {message!r} from {addr!r}")252253    print(f"Send: {message!r}")254    writer.write(data)255    await writer.drain()256257    print("Close the connection")258    writer.close()259260async def main():261    server = await asyncio.start_server(262        handle_echo, '127.0.0.1', 8888)263264    addr = server.sockets[0].getsockname()265    print(f'Serving on {addr}')266267    async with server:268        await server.serve_forever()269270asyncio.run(main())271```272273> **См. также**274>275> Пример [протокол TCP-эхо-сервера](https://python-all.ru/3.7/library/asyncio-protocol.html#asyncio-example-tcp-echo-server-protocol) использует метод [`loop.create_server()`](https://python-all.ru/3.7/library/asyncio-eventloop.html#asyncio.loop.create_server).276277### Получение HTTP-заголовков278279Простой пример получения HTTP-заголовков URL, переданного в командной строке:280281```python282import asyncio283import urllib.parse284import sys285286async def print_http_headers(url):287    url = urllib.parse.urlsplit(url)288    if url.scheme == 'https':289        reader, writer = await asyncio.open_connection(290            url.hostname, 443, ssl=True)291    else:292        reader, writer = await asyncio.open_connection(293            url.hostname, 80)294295    query = (296        f"HEAD {url.path or '/'} HTTP/1.0\r\n"297        f"Host: {url.hostname}\r\n"298        f"\r\n"299    )300301    writer.write(query.encode('latin-1'))302    while True:303        line = await reader.readline()304        if not line:305            break306307        line = line.decode('latin1').rstrip()308        if line:309            print(f'HTTP header> {line}')310311    # Игнорировать тело, закрыть сокет312    writer.close()313314url = sys.argv[1]315asyncio.run(print_http_headers(url))316```317318Использование:319320```python321python example.py http://example.com/path/page.html322```323324или с HTTPS:325326```python327python example.py https://example.com/path/page.html328```329330### Регистрация открытого сокета для ожидания данных с использованием потоков данных331332Корутина, ожидающая получения данных сокетом с помощью функции [`open_connection()`](https://python-all.ru/3.7/library/asyncio-stream.html#asyncio.open_connection):333334```python335import asyncio336import socket337338async def wait_for_data():339    # Получить ссылку на текущий цикл событий, так как340    # мы хотим получить доступ к низкоуровневым API.341    loop = asyncio.get_running_loop()342343    # Создать пару соединённых сокетов.344    rsock, wsock = socket.socketpair()345346    # Зарегистрировать открытый сокет для ожидания данных.347    reader, writer = await asyncio.open_connection(sock=rsock)348349    # Симулировать приём данных из сети350    loop.call_soon(wsock.send, 'abc'.encode())351352    # Ожидать данные353    data = await reader.read(100)354355    # Данные получены, всё готово: закрыть сокет356    print("Received:", data.decode())357    writer.close()358359    # Закрыть второй сокет360    wsock.close()361362asyncio.run(wait_for_data())363```364365> **См. также**366>367> Пример [регистрация открытого сокета для ожидания данных с использованием протокола](https://python-all.ru/3.7/library/asyncio-protocol.html#asyncio-example-create-connection) использует низкоуровневый протокол и метод [`loop.create_connection()`](https://python-all.ru/3.7/library/asyncio-eventloop.html#asyncio.loop.create_connection).368>369> Пример [наблюдения за файловым дескриптором на предмет событий чтения](https://python-all.ru/3.7/library/asyncio-eventloop.html#asyncio-example-watch-fd) использует низкоуровневый метод [`loop.add_reader()`](https://python-all.ru/3.7/library/asyncio-eventloop.html#asyncio.loop.add_reader) для наблюдения за файловым дескриптором.370