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

asyncio-stream.md

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

1> **Источник:** https://python-all.ru/3.9/library/asyncio-stream.html2>3> «Документация Python на русском» – неофициальный перевод официальной документации Python: версии от 2.6 до 3.16, полнотекстовый поиск, английский оригинал рядом с переводом. Эта Markdown-версия страницы предназначена для работы с LLM: вставьте её в ChatGPT, Claude или Cursor.45---67# Потоки данных89**Исходный код:** [Lib/asyncio/streams.py](https://python-all.ru/src/3.9/Lib/asyncio/streams.py)1011---1213Потоки данных – это высокоуровневые примитивы, готовые к использованию с async/await, для работы с сетевыми соединениями. Потоки данных позволяют отправлять и получать данные без использования колбэков или низкоуровневых протоколов и транспортов.1415Ниже приведён пример TCP-эхо-клиента, написанного с использованием asyncio потоков данных:1617```python18import asyncio1920async def tcp_echo_client(message):21    reader, writer = await asyncio.open_connection(22        '127.0.0.1', 8888)2324    print(f'Send: {message!r}')25    writer.write(message.encode())26    await writer.drain()2728    data = await reader.read(100)29    print(f'Received: {data.decode()!r}')3031    print('Close the connection')32    writer.close()33    await writer.wait_closed()3435asyncio.run(tcp_echo_client('Hello World!'))36```3738Смотрите также раздел [Примеры](https://python-all.ru/3.9/library/asyncio-stream.html#examples) ниже.3940Функции потоков данных4142Следующие функции asyncio верхнего уровня можно использовать для создания и работы с потоками данных:4344#### `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, happy_eyeballs_delay=None, interleave=None)`4546Устанавливает сетевое соединение и возвращает пару объектов `(reader, writer)`.4748Возвращаемые объекты *reader* и *writer* являются экземплярами классов [`StreamReader`](https://python-all.ru/3.9/library/asyncio-stream.html#asyncio.StreamReader) и [`StreamWriter`](https://python-all.ru/3.9/library/asyncio-stream.html#asyncio.StreamWriter).4950Аргумент *loop* необязателен и всегда определяется автоматически при ожидании этой функции из корутины.5152Параметр *limit* определяет ограничение размера буфера, используемого возвращаемым экземпляром [`StreamReader`](https://python-all.ru/3.9/library/asyncio-stream.html#asyncio.StreamReader). По умолчанию *limit* установлен в 64 КиБ.5354Остальные аргументы передаются напрямую в [`loop.create_connection()`](https://python-all.ru/3.9/library/asyncio-eventloop.html#asyncio.loop.create_connection).5556Новое в версии 3.7: параметр *ssl\_handshake\_timeout*.5758Новое в версии 3.8: Добавлены параметры *happy\_eyeballs\_delay* и *interleave*.5960#### `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)`6162Запускает сокет-сервер.6364Колбэк *client\_connected\_cb* вызывается при каждом установлении нового подключения клиента. Он получает пару `(reader, writer)` в качестве двух аргументов – экземпляры классов [`StreamReader`](https://python-all.ru/3.9/library/asyncio-stream.html#asyncio.StreamReader) и [`StreamWriter`](https://python-all.ru/3.9/library/asyncio-stream.html#asyncio.StreamWriter).6566*client\_connected\_cb* может быть обычным вызываемым объектом или [корутинной функцией](https://python-all.ru/3.9/library/asyncio-task.html#coroutine); если это корутинная функция, она будет автоматически запланирована как [`Task`](https://python-all.ru/3.9/library/asyncio-task.html#asyncio.Task).6768Аргумент *loop* необязателен и всегда определяется автоматически при ожидании этого метода из корутины.6970Параметр *limit* определяет ограничение размера буфера, используемого возвращаемым экземпляром [`StreamReader`](https://python-all.ru/3.9/library/asyncio-stream.html#asyncio.StreamReader). По умолчанию *limit* установлен в 64 КиБ.7172Остальные аргументы передаются напрямую в [`loop.create_server()`](https://python-all.ru/3.9/library/asyncio-eventloop.html#asyncio.loop.create_server).7374Новое в версии 3.7: параметры *ssl\_handshake\_timeout* и *start\_serving*.7576Unix-сокеты7778#### `coroutine asyncio.open_unix_connection(path=None, *, loop=None, limit=None, ssl=None, sock=None, server_hostname=None, ssl_handshake_timeout=None)`7980Устанавливает соединение через Unix-сокет и возвращает пару `(reader, writer)`.8182Аналогично [`open_connection()`](https://python-all.ru/3.9/library/asyncio-stream.html#asyncio.open_connection), но работает с Unix-сокетами.8384См. также документацию [`loop.create_unix_connection()`](https://python-all.ru/3.9/library/asyncio-eventloop.html#asyncio.loop.create_unix_connection).8586[Доступность](https://python-all.ru/3.9/library/intro.html#availability): Unix.8788Новое в версии 3.7: параметр *ssl\_handshake\_timeout*.8990Изменено в версии 3.7: Параметр *path* теперь может быть [объектом, подобным пути](https://python-all.ru/3.9/glossary.html#term-path-like-object)9192#### `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)`9394Запуск сервера Unix-сокетов.9596Аналогично [`start_server()`](https://python-all.ru/3.9/library/asyncio-stream.html#asyncio.start_server), но работает с Unix-сокетами.9798См. также документацию [`loop.create_unix_server()`](https://python-all.ru/3.9/library/asyncio-eventloop.html#asyncio.loop.create_unix_server).99100[Доступность](https://python-all.ru/3.9/library/intro.html#availability): Unix.101102Новое в версии 3.7: параметры *ssl\_handshake\_timeout* и *start\_serving*.103104Изменено в версии 3.7: Параметр *path* теперь может быть [объектом, подобным пути](https://python-all.ru/3.9/glossary.html#term-path-like-object).105106## StreamReader107108#### `class asyncio.StreamReader`109110Представляет объект чтения, предоставляющий API для чтения данных из потока ввода-вывода.111112Не рекомендуется создавать объекты *StreamReader* напрямую; вместо этого используйте [`open_connection()`](https://python-all.ru/3.9/library/asyncio-stream.html#asyncio.open_connection) и [`start_server()`](https://python-all.ru/3.9/library/asyncio-stream.html#asyncio.start_server).113114#### `coroutine read(n=-1)`115116Читает до *n* байт. Если *n* не указан или равен `-1`, читает до EOF и возвращает все прочитанные байты.117118Если получен EOF и внутренний буфер пуст, возвращает пустой объект `bytes`.119120#### `coroutine readline()`121122Читает одну строку, где «строка» – это последовательность байтов, заканчивающаяся `\n`.123124Если получен EOF и `\n` не найден, метод возвращает частично прочитанные данные.125126Если получен EOF и внутренний буфер пуст, возвращается пустой объект `bytes`.127128#### `coroutine readexactly(n)`129130Прочитать ровно *n* байт.131132Возбуждается [`IncompleteReadError`](https://python-all.ru/3.9/library/asyncio-exceptions.html#asyncio.IncompleteReadError), если EOF достигнут до того, как прочитано *n* байт. Используйте атрибут [`IncompleteReadError.partial`](https://python-all.ru/3.9/library/asyncio-exceptions.html#asyncio.IncompleteReadError.partial), чтобы получить частично прочитанные данные.133134#### `coroutine readuntil(separator=b'\n')`135136Читает данные из потока до тех пор, пока не будет найден *separator*.137138В случае успеха данные и разделитель удаляются из внутреннего буфера (потребляются). Возвращаемые данные включают разделитель в конце.139140Если объем прочитанных данных превышает настроенный лимит потока, возбуждается исключение [`LimitOverrunError`](https://python-all.ru/3.9/library/asyncio-exceptions.html#asyncio.LimitOverrunError), а данные остаются во внутреннем буфере и могут быть прочитаны снова.141142Если EOF достигнут до того, как найден полный разделитель, возбуждается исключение [`IncompleteReadError`](https://python-all.ru/3.9/library/asyncio-exceptions.html#asyncio.IncompleteReadError), и внутренний буфер сбрасывается. Атрибут [`IncompleteReadError.partial`](https://python-all.ru/3.9/library/asyncio-exceptions.html#asyncio.IncompleteReadError.partial) может содержать часть разделителя.143144Новое в версии 3.5.2.145146#### `at_eof()`147148Возвращает `True`, если буфер пуст и был вызван `feed_eof()`.149150## StreamWriter151152#### `class asyncio.StreamWriter`153154Представляет объект-писатель, предоставляющий API для записи данных в поток ввода-вывода.155156Не рекомендуется создавать объекты *StreamWriter* напрямую; вместо этого используйте [`open_connection()`](https://python-all.ru/3.9/library/asyncio-stream.html#asyncio.open_connection) и [`start_server()`](https://python-all.ru/3.9/library/asyncio-stream.html#asyncio.start_server).157158#### `write(data)`159160Метод пытается немедленно записать *data* в нижележащий сокет. Если это не удаётся, данные помещаются во внутренний буфер записи до тех пор, пока их нельзя будет отправить.161162Метод следует использовать вместе с методом `drain()`:163164```python165stream.write(data)166await stream.drain()167```168169#### `writelines(data)`170171Метод немедленно записывает список (или любой итерируемый объект) байт в нижележащий сокет. Если это не удаётся, данные помещаются во внутренний буфер записи до тех пор, пока их нельзя будет отправить.172173Метод следует использовать вместе с методом `drain()`:174175```python176stream.writelines(lines)177await stream.drain()178```179180#### `close()`181182Метод закрывает поток и нижележащий сокет.183184Метод следует использовать вместе с методом `wait_closed()`:185186```python187stream.close()188await stream.wait_closed()189```190191#### `can_write_eof()`192193Возвращает `True`, если нижележащий транспорт поддерживает метод [`write_eof()`](https://python-all.ru/3.9/library/asyncio-stream.html#asyncio.StreamWriter.write_eof), и `False` в противном случае.194195#### `write_eof()`196197Закрывает конец потока для записи после сброса буферизованных данных записи.198199#### `transport`200201Возвращает базовый транспорт asyncio.202203#### `get_extra_info(name, default=None)`204205Предоставляет доступ к дополнительной информации о транспорте; подробнее см. [`BaseTransport.get_extra_info()`](https://python-all.ru/3.9/library/asyncio-protocol.html#asyncio.BaseTransport.get_extra_info).206207#### `coroutine drain()`208209Ожидает, когда можно будет возобновить запись в поток данных. Пример:210211```python212writer.write(data)213await writer.drain()214```215216Это метод управления потоком, который взаимодействует с базовым буфером записи ввода-вывода. Когда размер буфера достигает верхней границы, *drain()* блокируется, пока размер буфера не уменьшится до нижней границы, после чего запись можно возобновить. Если ждать нечего, [`drain()`](https://python-all.ru/3.9/library/asyncio-stream.html#asyncio.StreamWriter.drain) возвращает управление немедленно.217218#### `is_closing()`219220Возвращает `True`, если поток данных закрыт или находится в процессе закрытия.221222Добавлено в версии 3.7.223224#### `coroutine wait_closed()`225226Ожидает закрытия потока данных.227228Должен вызываться после [`close()`](https://python-all.ru/3.9/library/asyncio-stream.html#asyncio.StreamWriter.close), чтобы дождаться закрытия нижележащего соединения.229230Добавлено в версии 3.7.231232## Примеры233234### TCP-эхо-клиент с использованием потоков данных235236TCP-эхо-клиент с использованием функции [`asyncio.open_connection()`](https://python-all.ru/3.9/library/asyncio-stream.html#asyncio.open_connection):237238```python239import asyncio240241async def tcp_echo_client(message):242    reader, writer = await asyncio.open_connection(243        '127.0.0.1', 8888)244245    print(f'Send: {message!r}')246    writer.write(message.encode())247248    data = await reader.read(100)249    print(f'Received: {data.decode()!r}')250251    print('Close the connection')252    writer.close()253254asyncio.run(tcp_echo_client('Hello World!'))255```256257> **См. также**258>259> Пример [протокол TCP-эхо-клиента](https://python-all.ru/3.9/library/asyncio-protocol.html#asyncio-example-tcp-echo-client-protocol) использует низкоуровневый метод [`loop.create_connection()`](https://python-all.ru/3.9/library/asyncio-eventloop.html#asyncio.loop.create_connection).260261### TCP-эхо-сервер с использованием потоков данных262263TCP-эхо-сервер с использованием функции [`asyncio.start_server()`](https://python-all.ru/3.9/library/asyncio-stream.html#asyncio.start_server):264265```python266import asyncio267268async def handle_echo(reader, writer):269    data = await reader.read(100)270    message = data.decode()271    addr = writer.get_extra_info('peername')272273    print(f"Received {message!r} from {addr!r}")274275    print(f"Send: {message!r}")276    writer.write(data)277    await writer.drain()278279    print("Close the connection")280    writer.close()281282async def main():283    server = await asyncio.start_server(284        handle_echo, '127.0.0.1', 8888)285286    addrs = ', '.join(str(sock.getsockname()) for sock in server.sockets)287    print(f'Serving on {addrs}')288289    async with server:290        await server.serve_forever()291292asyncio.run(main())293```294295> **См. также**296>297> Пример [протокол TCP-эхо-сервера](https://python-all.ru/3.9/library/asyncio-protocol.html#asyncio-example-tcp-echo-server-protocol) использует метод [`loop.create_server()`](https://python-all.ru/3.9/library/asyncio-eventloop.html#asyncio.loop.create_server).298299### Получение HTTP-заголовков300301Простой пример получения HTTP-заголовков URL, переданного в командной строке:302303```python304import asyncio305import urllib.parse306import sys307308async def print_http_headers(url):309    url = urllib.parse.urlsplit(url)310    if url.scheme == 'https':311        reader, writer = await asyncio.open_connection(312            url.hostname, 443, ssl=True)313    else:314        reader, writer = await asyncio.open_connection(315            url.hostname, 80)316317    query = (318        f"HEAD {url.path or '/'} HTTP/1.0\r\n"319        f"Host: {url.hostname}\r\n"320        f"\r\n"321    )322323    writer.write(query.encode('latin-1'))324    while True:325        line = await reader.readline()326        if not line:327            break328329        line = line.decode('latin1').rstrip()330        if line:331            print(f'HTTP header> {line}')332333    # Игнорировать тело, закрыть сокет334    writer.close()335336url = sys.argv[1]337asyncio.run(print_http_headers(url))338```339340Использование:341342```python343python example.py http://example.com/path/page.html344```345346или с HTTPS:347348```python349python example.py https://example.com/path/page.html350```351352### Регистрация открытого сокета для ожидания данных с использованием потоков данных353354Корутина, ожидающая получения данных сокетом с помощью функции [`open_connection()`](https://python-all.ru/3.9/library/asyncio-stream.html#asyncio.open_connection):355356```python357import asyncio358import socket359360async def wait_for_data():361    # Получить ссылку на текущий цикл событий, так как362    # мы хотим получить доступ к низкоуровневым API.363    loop = asyncio.get_running_loop()364365    # Создать пару соединённых сокетов.366    rsock, wsock = socket.socketpair()367368    # Зарегистрировать открытый сокет для ожидания данных.369    reader, writer = await asyncio.open_connection(sock=rsock)370371    # Симулировать приём данных из сети372    loop.call_soon(wsock.send, 'abc'.encode())373374    # Ожидать данные375    data = await reader.read(100)376377    # Данные получены, всё готово: закрыть сокет378    print("Received:", data.decode())379    writer.close()380381    # Закрыть второй сокет382    wsock.close()383384asyncio.run(wait_for_data())385```386387> **См. также**388>389> Пример [регистрация открытого сокета для ожидания данных с использованием протокола](https://python-all.ru/3.9/library/asyncio-protocol.html#asyncio-example-create-connection) использует низкоуровневый протокол и метод [`loop.create_connection()`](https://python-all.ru/3.9/library/asyncio-eventloop.html#asyncio.loop.create_connection).390>391> Пример [наблюдения за файловым дескриптором на предмет событий чтения](https://python-all.ru/3.9/library/asyncio-eventloop.html#asyncio-example-watch-fd) использует низкоуровневый метод [`loop.add_reader()`](https://python-all.ru/3.9/library/asyncio-eventloop.html#asyncio.loop.add_reader) для наблюдения за файловым дескриптором.392