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

asyncio-stream.md

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

1> **Источник:** https://python-all.ru/3.10/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.10/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.10/library/asyncio-stream.html#examples) ниже.3940Функции потоков данных4142Следующие функции asyncio верхнего уровня можно использовать для создания и работы с потоками данных:4344#### `coroutine asyncio.open_connection(host=None, port=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.10/library/asyncio-stream.html#asyncio.StreamReader) и [`StreamWriter`](https://python-all.ru/3.10/library/asyncio-stream.html#asyncio.StreamWriter).4950Параметр *limit* определяет ограничение размера буфера, используемого возвращаемым экземпляром [`StreamReader`](https://python-all.ru/3.10/library/asyncio-stream.html#asyncio.StreamReader). По умолчанию *limit* установлен в 64 КиБ.5152Остальные аргументы передаются напрямую в [`loop.create_connection()`](https://python-all.ru/3.10/library/asyncio-eventloop.html#asyncio.loop.create_connection).5354> **Примечание**55>56> Аргумент *sock* передаёт владение сокетом созданному [`StreamWriter`](https://python-all.ru/3.10/library/asyncio-stream.html#asyncio.StreamWriter). Чтобы закрыть сокет, вызовите его метод [`close()`](https://python-all.ru/3.10/library/asyncio-stream.html#asyncio.StreamWriter.close).5758Изменено в версии 3.7: Добавлен параметр *ssl\_handshake\_timeout*.5960Новое в версии 3.8: Добавлены параметры *happy\_eyeballs\_delay* и *interleave*.6162Изменено в версии 3.10: Удалён параметр *loop*.6364#### `coroutine asyncio.start_server(client_connected_cb, host=None, port=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)`6566Запускает сокет-сервер.6768Колбэк *client\_connected\_cb* вызывается при каждом установлении нового подключения клиента. Он получает пару `(reader, writer)` в качестве двух аргументов – экземпляры классов [`StreamReader`](https://python-all.ru/3.10/library/asyncio-stream.html#asyncio.StreamReader) и [`StreamWriter`](https://python-all.ru/3.10/library/asyncio-stream.html#asyncio.StreamWriter).6970*client\_connected\_cb* может быть обычным вызываемым объектом или [корутинной функцией](https://python-all.ru/3.10/library/asyncio-task.html#coroutine); если это корутинная функция, она будет автоматически запланирована как [`Task`](https://python-all.ru/3.10/library/asyncio-task.html#asyncio.Task).7172Параметр *limit* определяет ограничение размера буфера, используемого возвращаемым экземпляром [`StreamReader`](https://python-all.ru/3.10/library/asyncio-stream.html#asyncio.StreamReader). По умолчанию *limit* установлен в 64 КиБ.7374Остальные аргументы передаются напрямую в [`loop.create_server()`](https://python-all.ru/3.10/library/asyncio-eventloop.html#asyncio.loop.create_server).7576> **Примечание**77>78> Аргумент *sock* передаёт владение сокетом созданному серверу. Чтобы закрыть сокет, вызовите метод сервера [`close()`](https://python-all.ru/3.10/library/asyncio-eventloop.html#asyncio.Server.close).7980Изменено в версии 3.7: Добавлены параметры *ssl\_handshake\_timeout* и *start\_serving*.8182Изменено в версии 3.10: Удалён параметр *loop*.8384Unix-сокеты8586#### `coroutine asyncio.open_unix_connection(path=None, *, limit=None, ssl=None, sock=None, server_hostname=None, ssl_handshake_timeout=None)`8788Устанавливает соединение через Unix-сокет и возвращает пару `(reader, writer)`.8990Аналогично [`open_connection()`](https://python-all.ru/3.10/library/asyncio-stream.html#asyncio.open_connection), но работает с Unix-сокетами.9192См. также документацию [`loop.create_unix_connection()`](https://python-all.ru/3.10/library/asyncio-eventloop.html#asyncio.loop.create_unix_connection).9394> **Примечание**95>96> Аргумент *sock* передаёт владение сокетом созданному [`StreamWriter`](https://python-all.ru/3.10/library/asyncio-stream.html#asyncio.StreamWriter). Чтобы закрыть сокет, вызовите его метод [`close()`](https://python-all.ru/3.10/library/asyncio-stream.html#asyncio.StreamWriter.close).9798[Доступность](https://python-all.ru/3.10/library/intro.html#availability): Unix.99100Изменено в версии 3.7: Добавлен параметр *ssl\_handshake\_timeout*. Параметр *path* теперь может быть [объектом, подобным пути](https://python-all.ru/3.10/glossary.html#term-path-like-object).101102Изменено в версии 3.10: Удалён параметр *loop*.103104#### `coroutine asyncio.start_unix_server(client_connected_cb, path=None, *, limit=None, sock=None, backlog=100, ssl=None, ssl_handshake_timeout=None, start_serving=True)`105106Запуск сервера Unix-сокетов.107108Аналогично [`start_server()`](https://python-all.ru/3.10/library/asyncio-stream.html#asyncio.start_server), но работает с Unix-сокетами.109110См. также документацию [`loop.create_unix_server()`](https://python-all.ru/3.10/library/asyncio-eventloop.html#asyncio.loop.create_unix_server).111112> **Примечание**113>114> Аргумент *sock* передаёт владение сокетом созданному серверу. Чтобы закрыть сокет, вызовите метод сервера [`close()`](https://python-all.ru/3.10/library/asyncio-eventloop.html#asyncio.Server.close).115116[Доступность](https://python-all.ru/3.10/library/intro.html#availability): Unix.117118Изменено в версии 3.7: Добавлены параметры *ssl\_handshake\_timeout* и *start\_serving*. Параметр *path* теперь может быть [объектом, подобным пути](https://python-all.ru/3.10/glossary.html#term-path-like-object).119120Изменено в версии 3.10: Удалён параметр *loop*.121122## StreamReader123124#### `class asyncio.StreamReader`125126Представляет объект чтения, предоставляющий API для чтения данных из потока ввода-вывода. Как [асинхронный итерируемый объект](https://python-all.ru/3.10/glossary.html#term-asynchronous-iterable), этот объект поддерживает инструкцию [`async for`](https://python-all.ru/3.10/reference/compound_stmts.html#async-for).127128Не рекомендуется создавать объекты *StreamReader* напрямую; вместо этого используйте [`open_connection()`](https://python-all.ru/3.10/library/asyncio-stream.html#asyncio.open_connection) и [`start_server()`](https://python-all.ru/3.10/library/asyncio-stream.html#asyncio.start_server).129130#### `coroutine read(n=- 1)`131132Читает до *n* байт из потока.133134Если *n* не указан или равен `-1`, читает до EOF, затем возвращает все прочитанные [`bytes`](https://python-all.ru/3.10/library/stdtypes.html#bytes). Если получен EOF и внутренний буфер пуст, возвращает пустой объект `bytes`.135136Если *n* равен `0`, немедленно возвращает пустой объект `bytes`.137138Если *n* положительный, возвращает не более *n* доступных `bytes`, как только во внутреннем буфере появляется хотя бы 1 байт. Если EOF получен до чтения хотя бы одного байта, возвращается пустой объект `bytes`.139140#### `coroutine readline()`141142Читает одну строку, где «строка» – это последовательность байтов, заканчивающаяся `\n`.143144Если получен EOF и `\n` не найден, метод возвращает частично прочитанные данные.145146Если получен EOF и внутренний буфер пуст, возвращается пустой объект `bytes`.147148#### `coroutine readexactly(n)`149150Прочитать ровно *n* байт.151152Возбуждается [`IncompleteReadError`](https://python-all.ru/3.10/library/asyncio-exceptions.html#asyncio.IncompleteReadError), если EOF достигнут до того, как прочитано *n* байт. Используйте атрибут [`IncompleteReadError.partial`](https://python-all.ru/3.10/library/asyncio-exceptions.html#asyncio.IncompleteReadError.partial), чтобы получить частично прочитанные данные.153154#### `coroutine readuntil(separator=b'\n')`155156Читает данные из потока до тех пор, пока не будет найден *separator*.157158В случае успеха данные и разделитель удаляются из внутреннего буфера (потребляются). Возвращаемые данные включают разделитель в конце.159160Если объем прочитанных данных превышает настроенный лимит потока, возбуждается исключение [`LimitOverrunError`](https://python-all.ru/3.10/library/asyncio-exceptions.html#asyncio.LimitOverrunError), а данные остаются во внутреннем буфере и могут быть прочитаны снова.161162Если EOF достигнут до того, как найден полный разделитель, возбуждается исключение [`IncompleteReadError`](https://python-all.ru/3.10/library/asyncio-exceptions.html#asyncio.IncompleteReadError), и внутренний буфер сбрасывается. Атрибут [`IncompleteReadError.partial`](https://python-all.ru/3.10/library/asyncio-exceptions.html#asyncio.IncompleteReadError.partial) может содержать часть разделителя.163164Новое в версии 3.5.2.165166#### `at_eof()`167168Возвращает `True`, если буфер пуст и был вызван `feed_eof()`.169170## StreamWriter171172#### `class asyncio.StreamWriter`173174Представляет объект-писатель, предоставляющий API для записи данных в поток ввода-вывода.175176Не рекомендуется создавать объекты *StreamWriter* напрямую; вместо этого используйте [`open_connection()`](https://python-all.ru/3.10/library/asyncio-stream.html#asyncio.open_connection) и [`start_server()`](https://python-all.ru/3.10/library/asyncio-stream.html#asyncio.start_server).177178#### `write(data)`179180Метод пытается немедленно записать *data* в нижележащий сокет. Если это не удаётся, данные помещаются во внутренний буфер записи до тех пор, пока их нельзя будет отправить.181182Метод следует использовать вместе с методом `drain()`:183184```python185stream.write(data)186await stream.drain()187```188189#### `writelines(data)`190191Метод немедленно записывает список (или любой итерируемый объект) байт в нижележащий сокет. Если это не удаётся, данные помещаются во внутренний буфер записи до тех пор, пока их нельзя будет отправить.192193Метод следует использовать вместе с методом `drain()`:194195```python196stream.writelines(lines)197await stream.drain()198```199200#### `close()`201202Метод закрывает поток и нижележащий сокет.203204Метод следует использовать, хотя это и не обязательно, вместе с методом `wait_closed()`:205206```python207stream.close()208await stream.wait_closed()209```210211#### `can_write_eof()`212213Возвращает `True`, если нижележащий транспорт поддерживает метод [`write_eof()`](https://python-all.ru/3.10/library/asyncio-stream.html#asyncio.StreamWriter.write_eof), и `False` в противном случае.214215#### `write_eof()`216217Закрывает конец потока для записи после сброса буферизованных данных записи.218219#### `transport`220221Возвращает базовый транспорт asyncio.222223#### `get_extra_info(name, default=None)`224225Предоставляет доступ к дополнительной информации о транспорте; подробнее см. [`BaseTransport.get_extra_info()`](https://python-all.ru/3.10/library/asyncio-protocol.html#asyncio.BaseTransport.get_extra_info).226227#### `coroutine drain()`228229Ожидает, когда можно будет возобновить запись в поток данных. Пример:230231```python232writer.write(data)233await writer.drain()234```235236Это метод управления потоком, который взаимодействует с базовым буфером записи ввода-вывода. Когда размер буфера достигает верхней границы, *drain()* блокируется, пока размер буфера не уменьшится до нижней границы, после чего запись можно возобновить. Если ждать нечего, [`drain()`](https://python-all.ru/3.10/library/asyncio-stream.html#asyncio.StreamWriter.drain) возвращает управление немедленно.237238#### `is_closing()`239240Возвращает `True`, если поток данных закрыт или находится в процессе закрытия.241242Добавлено в версии 3.7.243244#### `coroutine wait_closed()`245246Ожидает закрытия потока данных.247248Должен вызываться после [`close()`](https://python-all.ru/3.10/library/asyncio-stream.html#asyncio.StreamWriter.close), чтобы дождаться закрытия базового соединения и гарантировать, что все данные будут сброшены перед, например, выходом из программы.249250Добавлено в версии 3.7.251252## Примеры253254### TCP-эхо-клиент с использованием потоков данных255256TCP-эхо-клиент с использованием функции [`asyncio.open_connection()`](https://python-all.ru/3.10/library/asyncio-stream.html#asyncio.open_connection):257258```python259import asyncio260261async def tcp_echo_client(message):262    reader, writer = await asyncio.open_connection(263        '127.0.0.1', 8888)264265    print(f'Send: {message!r}')266    writer.write(message.encode())267268    data = await reader.read(100)269    print(f'Received: {data.decode()!r}')270271    print('Close the connection')272    writer.close()273    await writer.wait_closed()274275asyncio.run(tcp_echo_client('Hello World!'))276```277278> **См. также**279>280> Пример [протокол TCP-эхо-клиента](https://python-all.ru/3.10/library/asyncio-protocol.html#asyncio-example-tcp-echo-client-protocol) использует низкоуровневый метод [`loop.create_connection()`](https://python-all.ru/3.10/library/asyncio-eventloop.html#asyncio.loop.create_connection).281282### TCP-эхо-сервер с использованием потоков данных283284TCP-эхо-сервер с использованием функции [`asyncio.start_server()`](https://python-all.ru/3.10/library/asyncio-stream.html#asyncio.start_server):285286```python287import asyncio288289async def handle_echo(reader, writer):290    data = await reader.read(100)291    message = data.decode()292    addr = writer.get_extra_info('peername')293294    print(f"Received {message!r} from {addr!r}")295296    print(f"Send: {message!r}")297    writer.write(data)298    await writer.drain()299300    print("Close the connection")301    writer.close()302    await writer.wait_closed()303304async def main():305    server = await asyncio.start_server(306        handle_echo, '127.0.0.1', 8888)307308    addrs = ', '.join(str(sock.getsockname()) for sock in server.sockets)309    print(f'Serving on {addrs}')310311    async with server:312        await server.serve_forever()313314asyncio.run(main())315```316317> **См. также**318>319> Пример [протокол TCP-эхо-сервера](https://python-all.ru/3.10/library/asyncio-protocol.html#asyncio-example-tcp-echo-server-protocol) использует метод [`loop.create_server()`](https://python-all.ru/3.10/library/asyncio-eventloop.html#asyncio.loop.create_server).320321### Получение HTTP-заголовков322323Простой пример получения HTTP-заголовков URL, переданного в командной строке:324325```python326import asyncio327import urllib.parse328import sys329330async def print_http_headers(url):331    url = urllib.parse.urlsplit(url)332    if url.scheme == 'https':333        reader, writer = await asyncio.open_connection(334            url.hostname, 443, ssl=True)335    else:336        reader, writer = await asyncio.open_connection(337            url.hostname, 80)338339    query = (340        f"HEAD {url.path or '/'} HTTP/1.0\r\n"341        f"Host: {url.hostname}\r\n"342        f"\r\n"343    )344345    writer.write(query.encode('latin-1'))346    while True:347        line = await reader.readline()348        if not line:349            break350351        line = line.decode('latin1').rstrip()352        if line:353            print(f'HTTP header> {line}')354355    # Игнорировать тело, закрыть сокет356    writer.close()357    await writer.wait_closed()358359url = sys.argv[1]360asyncio.run(print_http_headers(url))361```362363Использование:364365```python366python example.py http://example.com/path/page.html367```368369или с HTTPS:370371```python372python example.py https://example.com/path/page.html373```374375### Регистрация открытого сокета для ожидания данных с использованием потоков данных376377Корутина, ожидающая получения данных сокетом с помощью функции [`open_connection()`](https://python-all.ru/3.10/library/asyncio-stream.html#asyncio.open_connection):378379```python380import asyncio381import socket382383async def wait_for_data():384    # Получить ссылку на текущий цикл событий, так как385    # мы хотим получить доступ к низкоуровневым API.386    loop = asyncio.get_running_loop()387388    # Создать пару соединённых сокетов.389    rsock, wsock = socket.socketpair()390391    # Зарегистрировать открытый сокет для ожидания данных.392    reader, writer = await asyncio.open_connection(sock=rsock)393394    # Симулировать приём данных из сети395    loop.call_soon(wsock.send, 'abc'.encode())396397    # Ожидать данные398    data = await reader.read(100)399400    # Данные получены, всё готово: закрыть сокет401    print("Received:", data.decode())402    writer.close()403    await writer.wait_closed()404405    # Закрыть второй сокет406    wsock.close()407408asyncio.run(wait_for_data())409```410411> **См. также**412>413> Пример [регистрация открытого сокета для ожидания данных с использованием протокола](https://python-all.ru/3.10/library/asyncio-protocol.html#asyncio-example-create-connection) использует низкоуровневый протокол и метод [`loop.create_connection()`](https://python-all.ru/3.10/library/asyncio-eventloop.html#asyncio.loop.create_connection).414>415> Пример [наблюдения за файловым дескриптором на предмет событий чтения](https://python-all.ru/3.10/library/asyncio-eventloop.html#asyncio-example-watch-fd) использует низкоуровневый метод [`loop.add_reader()`](https://python-all.ru/3.10/library/asyncio-eventloop.html#asyncio.loop.add_reader) для наблюдения за файловым дескриптором.416