asyncio-stream.md
1> **Источник:** https://python-all.ru/3.15/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.15/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.15/library/asyncio-stream.html#examples) ниже.3940Функции потоков данных4142Следующие функции asyncio верхнего уровня можно использовать для создания и работы с потоками данных:4344#### `async 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, ssl_shutdown_timeout=None, happy_eyeballs_delay=None, interleave=None)`4546Устанавливает сетевое соединение и возвращает пару объектов `(reader, writer)`.4748Возвращаемые объекты *reader* и *writer* являются экземплярами классов [`StreamReader`](https://python-all.ru/3.15/library/asyncio-stream.html#asyncio.StreamReader) и [`StreamWriter`](https://python-all.ru/3.15/library/asyncio-stream.html#asyncio.StreamWriter).4950Параметр *limit* определяет ограничение размера буфера, используемого возвращаемым экземпляром [`StreamReader`](https://python-all.ru/3.15/library/asyncio-stream.html#asyncio.StreamReader). По умолчанию *limit* установлен в 64 КиБ.5152Остальные аргументы передаются напрямую в [`loop.create_connection()`](https://python-all.ru/3.15/library/asyncio-eventloop.html#asyncio.loop.create_connection).5354> **Примечание**55>56> Аргумент *sock* передаёт владение сокетом созданному [`StreamWriter`](https://python-all.ru/3.15/library/asyncio-stream.html#asyncio.StreamWriter). Чтобы закрыть сокет, вызовите его метод [`close()`](https://python-all.ru/3.15/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Изменено в версии 3.11: Добавлен параметр *ssl\_shutdown\_timeout*.6566#### `async 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, keep_alive=None, ssl_handshake_timeout=None, ssl_shutdown_timeout=None, start_serving=True)`6768Запускает сокет-сервер.6970Колбэк *client\_connected\_cb* вызывается при каждом установлении нового подключения клиента. Он получает пару `(reader, writer)` в качестве двух аргументов – экземпляры классов [`StreamReader`](https://python-all.ru/3.15/library/asyncio-stream.html#asyncio.StreamReader) и [`StreamWriter`](https://python-all.ru/3.15/library/asyncio-stream.html#asyncio.StreamWriter).7172*client\_connected\_cb* может быть обычным вызываемым объектом или [корутинной функцией](https://python-all.ru/3.15/library/asyncio-task.html#coroutine); если это корутинная функция, она будет автоматически запланирована как [`Task`](https://python-all.ru/3.15/library/asyncio-task.html#asyncio.Task).7374Параметр *limit* определяет ограничение размера буфера, используемого возвращаемым экземпляром [`StreamReader`](https://python-all.ru/3.15/library/asyncio-stream.html#asyncio.StreamReader). По умолчанию *limit* установлен в 64 КиБ.7576Остальные аргументы передаются напрямую в [`loop.create_server()`](https://python-all.ru/3.15/library/asyncio-eventloop.html#asyncio.loop.create_server).7778> **Примечание**79>80> Аргумент *sock* передаёт владение сокетом созданному серверу. Чтобы закрыть сокет, вызовите метод сервера [`close()`](https://python-all.ru/3.15/library/asyncio-eventloop.html#asyncio.Server.close).8182Изменено в версии 3.7: Добавлены параметры *ssl\_handshake\_timeout* и *start\_serving*.8384Изменено в версии 3.10: Удалён параметр *loop*.8586Изменено в версии 3.11: Добавлен параметр *ssl\_shutdown\_timeout*.8788Изменено в версии 3.13: Добавлен параметр *keep\_alive*.8990Unix-сокеты9192#### `async asyncio.open_unix_connection(path=None, *, limit=None, ssl=None, sock=None, server_hostname=None, ssl_handshake_timeout=None, ssl_shutdown_timeout=None)`9394Устанавливает соединение через Unix-сокет и возвращает пару `(reader, writer)`.9596Аналогично [`open_connection()`](https://python-all.ru/3.15/library/asyncio-stream.html#asyncio.open_connection), но работает с Unix-сокетами.9798См. также документацию [`loop.create_unix_connection()`](https://python-all.ru/3.15/library/asyncio-eventloop.html#asyncio.loop.create_unix_connection).99100> **Примечание**101>102> Аргумент *sock* передаёт владение сокетом созданному [`StreamWriter`](https://python-all.ru/3.15/library/asyncio-stream.html#asyncio.StreamWriter). Чтобы закрыть сокет, вызовите его метод [`close()`](https://python-all.ru/3.15/library/asyncio-stream.html#asyncio.StreamWriter.close).103104[Доступность](https://python-all.ru/3.15/library/intro.html#availability): Unix.105106Изменено в версии 3.7: Добавлен параметр *ssl\_handshake\_timeout*. Параметр *path* теперь может быть [объектом, подобным пути](https://python-all.ru/3.15/glossary.html#term-path-like-object).107108Изменено в версии 3.10: Удалён параметр *loop*.109110Изменено в версии 3.11: Добавлен параметр *ssl\_shutdown\_timeout*.111112#### `async asyncio.start_unix_server(client_connected_cb, path=None, *, limit=None, sock=None, backlog=100, ssl=None, ssl_handshake_timeout=None, ssl_shutdown_timeout=None, start_serving=True, cleanup_socket=True)`113114Запуск сервера Unix-сокетов.115116Аналогично [`start_server()`](https://python-all.ru/3.15/library/asyncio-stream.html#asyncio.start_server), но работает с Unix-сокетами.117118Если *cleanup\_socket* равен true, то Unix-сокет будет автоматически удалён из файловой системы при закрытии сервера, если только сокет не был заменён после создания сервера.119120См. также документацию [`loop.create_unix_server()`](https://python-all.ru/3.15/library/asyncio-eventloop.html#asyncio.loop.create_unix_server).121122> **Примечание**123>124> Аргумент *sock* передаёт владение сокетом созданному серверу. Чтобы закрыть сокет, вызовите метод сервера [`close()`](https://python-all.ru/3.15/library/asyncio-eventloop.html#asyncio.Server.close).125126[Доступность](https://python-all.ru/3.15/library/intro.html#availability): Unix.127128Изменено в версии 3.7: Добавлены параметры *ssl\_handshake\_timeout* и *start\_serving*. Параметр *path* теперь может быть [объектом, подобным пути](https://python-all.ru/3.15/glossary.html#term-path-like-object).129130Изменено в версии 3.10: Удалён параметр *loop*.131132Изменено в версии 3.11: Добавлен параметр *ssl\_shutdown\_timeout*.133134Изменено в версии 3.13: Добавлен параметр *cleanup\_socket*.135136## StreamReader137138#### `class asyncio.StreamReader`139140Представляет объект чтения, предоставляющий API для чтения данных из потока ввода-вывода. Как [асинхронный итерируемый объект](https://python-all.ru/3.15/glossary.html#term-asynchronous-iterable), этот объект поддерживает инструкцию [`async for`](https://python-all.ru/3.15/reference/compound_stmts.html#async-for).141142Не рекомендуется создавать объекты *StreamReader* напрямую; вместо этого используйте [`open_connection()`](https://python-all.ru/3.15/library/asyncio-stream.html#asyncio.open_connection) и [`start_server()`](https://python-all.ru/3.15/library/asyncio-stream.html#asyncio.start_server).143144#### `feed_eof()`145146Подтверждает конец файла (EOF).147148#### `async read(n=-1)`149150Читает до *n* байт из потока.151152Если *n* не указан или равен `-1`, читает до EOF, затем возвращает все прочитанные [`bytes`](https://python-all.ru/3.15/library/stdtypes.html#bytes). Если получен EOF и внутренний буфер пуст, возвращает пустой объект `bytes`.153154Если *n* равен `0`, немедленно возвращает пустой объект `bytes`.155156Если *n* положительный, возвращает не более *n* доступных `bytes`, как только во внутреннем буфере появляется хотя бы 1 байт. Если EOF получен до чтения хотя бы одного байта, возвращается пустой объект `bytes`.157158#### `async readline()`159160Читает одну строку, где «строка» – это последовательность байтов, заканчивающаяся `\n`.161162Если получен EOF и `\n` не найден, метод возвращает частично прочитанные данные.163164Если получен EOF и внутренний буфер пуст, возвращается пустой объект `bytes`.165166#### `async readexactly(n)`167168Прочитать ровно *n* байт.169170Возбуждается [`IncompleteReadError`](https://python-all.ru/3.15/library/asyncio-exceptions.html#asyncio.IncompleteReadError), если EOF достигнут до того, как прочитано *n* байт. Используйте атрибут [`IncompleteReadError.partial`](https://python-all.ru/3.15/library/asyncio-exceptions.html#asyncio.IncompleteReadError.partial), чтобы получить частично прочитанные данные.171172#### `async readuntil(separator=b'\n')`173174Читает данные из потока до тех пор, пока не будет найден *separator*.175176В случае успеха данные и разделитель удаляются из внутреннего буфера (потребляются). Возвращаемые данные включают разделитель в конце.177178Если объем прочитанных данных превышает настроенный лимит потока, возбуждается исключение [`LimitOverrunError`](https://python-all.ru/3.15/library/asyncio-exceptions.html#asyncio.LimitOverrunError), а данные остаются во внутреннем буфере и могут быть прочитаны снова.179180Если EOF достигнут до того, как найден полный разделитель, возбуждается исключение [`IncompleteReadError`](https://python-all.ru/3.15/library/asyncio-exceptions.html#asyncio.IncompleteReadError), и внутренний буфер сбрасывается. Атрибут [`IncompleteReadError.partial`](https://python-all.ru/3.15/library/asyncio-exceptions.html#asyncio.IncompleteReadError.partial) может содержать часть разделителя.181182*separator* также может быть кортежем разделителей. В этом случае возвращаемое значение будет кратчайшей возможной строкой, у которой любой из разделителей является суффиксом. Для целей [`LimitOverrunError`](https://python-all.ru/3.15/library/asyncio-exceptions.html#asyncio.LimitOverrunError) кратчайшим возможным разделителем считается тот, который совпал.183184Добавлено в версии 3.5.2.185186Изменено в версии 3.13: Параметр *separator* теперь может быть [`tuple`](https://python-all.ru/3.15/library/stdtypes.html#tuple) разделителей.187188#### `at_eof()`189190Возвращает `True`, если буфер пуст и был вызван [`feed_eof()`](https://python-all.ru/3.15/library/asyncio-stream.html#asyncio.StreamReader.feed_eof).191192## StreamWriter193194#### `class asyncio.StreamWriter`195196Представляет объект-писатель, предоставляющий API для записи данных в поток ввода-вывода.197198Не рекомендуется создавать объекты *StreamWriter* напрямую; вместо этого используйте [`open_connection()`](https://python-all.ru/3.15/library/asyncio-stream.html#asyncio.open_connection) и [`start_server()`](https://python-all.ru/3.15/library/asyncio-stream.html#asyncio.start_server).199200#### `write(data)`201202Метод пытается немедленно записать *data* в нижележащий сокет. Если это не удаётся, данные помещаются во внутренний буфер записи до тех пор, пока их нельзя будет отправить.203204Буфер *data* должен быть объектом bytes, bytearray или C-непрерывным одномерным memoryview.205206Метод следует использовать вместе с методом `drain()`:207208```python209stream.write(data)210await stream.drain()211```212213#### `writelines(data)`214215Метод немедленно записывает список (или любой итерируемый объект) байт в нижележащий сокет. Если это не удаётся, данные помещаются во внутренний буфер записи до тех пор, пока их нельзя будет отправить.216217Метод следует использовать вместе с методом `drain()`:218219```python220stream.writelines(lines)221await stream.drain()222```223224#### `close()`225226Метод закрывает поток и нижележащий сокет.227228Метод следует использовать, хотя это и не обязательно, вместе с методом `wait_closed()`:229230```python231stream.close()232await stream.wait_closed()233```234235#### `can_write_eof()`236237Возвращает `True`, если нижележащий транспорт поддерживает метод [`write_eof()`](https://python-all.ru/3.15/library/asyncio-stream.html#asyncio.StreamWriter.write_eof), и `False` в противном случае.238239#### `write_eof()`240241Закрывает конец потока для записи после сброса буферизованных данных записи.242243#### `transport`244245Возвращает базовый транспорт asyncio.246247#### `get_extra_info(name, default=None)`248249Предоставляет доступ к дополнительной информации о транспорте; подробнее см. [`BaseTransport.get_extra_info()`](https://python-all.ru/3.15/library/asyncio-protocol.html#asyncio.BaseTransport.get_extra_info).250251#### `async drain()`252253Ожидает, когда можно будет возобновить запись в поток данных. Пример:254255```python256writer.write(data)257await writer.drain()258```259260Это метод управления потоком, который взаимодействует с базовым буфером записи ввода-вывода. Когда размер буфера достигает верхней границы, *drain()* блокируется, пока размер буфера не уменьшится до нижней границы, после чего запись можно возобновить. Если ждать нечего, `drain()` возвращает управление немедленно.261262#### `async start_tls(sslcontext, *, server_hostname=None, ssl_handshake_timeout=None, ssl_shutdown_timeout=None)`263264Обновляет существующее потоковое соединение до TLS.265266Параметры:267268- *sslcontext*: настроенный экземпляр [`SSLContext`](https://python-all.ru/3.15/library/ssl.html#ssl.SSLContext).269- *server\_hostname*: задаёт или переопределяет имя узла, с которым будет сверяться сертификат целевого сервера.270- *ssl\_handshake\_timeout* – время в секундах ожидания завершения рукопожатия TLS перед разрывом соединения. `60.0` секунд, если `None` (по умолчанию).271- *ssl\_shutdown\_timeout* – время в секундах ожидания завершения закрытия SSL перед разрывом соединения. `30.0` секунд, если `None` (по умолчанию).272273Добавлено в версии 3.12.274275Изменено в версии 3.12: Добавлен параметр *ssl\_shutdown\_timeout*.276277#### `is_closing()`278279Возвращает `True`, если поток данных закрыт или находится в процессе закрытия.280281Добавлено в версии 3.7.282283#### `async wait_closed()`284285Ожидает закрытия потока данных.286287Должен вызываться после [`close()`](https://python-all.ru/3.15/library/asyncio-stream.html#asyncio.StreamWriter.close), чтобы дождаться закрытия базового соединения и гарантировать, что все данные будут сброшены перед, например, выходом из программы.288289Добавлено в версии 3.7.290291## Примеры292293### TCP-эхо-клиент с использованием потоков данных294295TCP-эхо-клиент с использованием функции [`asyncio.open_connection()`](https://python-all.ru/3.15/library/asyncio-stream.html#asyncio.open_connection):296297```python298import asyncio299300async def tcp_echo_client(message):301 reader, writer = await asyncio.open_connection(302 '127.0.0.1', 8888)303304 print(f'Send: {message!r}')305 writer.write(message.encode())306 await writer.drain()307308 data = await reader.read(100)309 print(f'Received: {data.decode()!r}')310311 print('Close the connection')312 writer.close()313 await writer.wait_closed()314315asyncio.run(tcp_echo_client('Hello World!'))316```317318> **См. также**319>320> Пример [протокол TCP-эхо-клиента](https://python-all.ru/3.15/library/asyncio-protocol.html#asyncio-example-tcp-echo-client-protocol) использует низкоуровневый метод [`loop.create_connection()`](https://python-all.ru/3.15/library/asyncio-eventloop.html#asyncio.loop.create_connection).321322### TCP-эхо-сервер с использованием потоков данных323324TCP-эхо-сервер с использованием функции [`asyncio.start_server()`](https://python-all.ru/3.15/library/asyncio-stream.html#asyncio.start_server):325326```python327import asyncio328329async def handle_echo(reader, writer):330 data = await reader.read(100)331 message = data.decode()332 addr = writer.get_extra_info('peername')333334 print(f"Received {message!r} from {addr!r}")335336 print(f"Send: {message!r}")337 writer.write(data)338 await writer.drain()339340 print("Close the connection")341 writer.close()342 await writer.wait_closed()343344async def main():345 server = await asyncio.start_server(346 handle_echo, '127.0.0.1', 8888)347348 addrs = ', '.join(str(sock.getsockname()) for sock in server.sockets)349 print(f'Serving on {addrs}')350351 async with server:352 await server.serve_forever()353354asyncio.run(main())355```356357> **См. также**358>359> Пример [протокол TCP-эхо-сервера](https://python-all.ru/3.15/library/asyncio-protocol.html#asyncio-example-tcp-echo-server-protocol) использует метод [`loop.create_server()`](https://python-all.ru/3.15/library/asyncio-eventloop.html#asyncio.loop.create_server).360361### Получение HTTP-заголовков362363Простой пример получения HTTP-заголовков URL, переданного в командной строке:364365```python366import asyncio367import urllib.parse368import sys369370async def print_http_headers(url):371 url = urllib.parse.urlsplit(url)372 if url.scheme == 'https':373 reader, writer = await asyncio.open_connection(374 url.hostname, 443, ssl=True)375 else:376 reader, writer = await asyncio.open_connection(377 url.hostname, 80)378379 query = (380 f"HEAD {url.path or '/'} HTTP/1.0\r\n"381 f"Host: {url.hostname}\r\n"382 f"\r\n"383 )384385 writer.write(query.encode('latin-1'))386 while True:387 line = await reader.readline()388 if not line:389 break390391 line = line.decode('latin1').rstrip()392 if line:393 print(f'HTTP header> {line}')394395 # Игнорировать тело, закрыть сокет396 writer.close()397 await writer.wait_closed()398399url = sys.argv[1]400asyncio.run(print_http_headers(url))401```402403Использование:404405```python406python example.py http://example.com/path/page.html407```408409или с HTTPS:410411```python412python example.py https://example.com/path/page.html413```414415### Регистрация открытого сокета для ожидания данных с использованием потоков данных416417Корутина, ожидающая получения данных сокетом с помощью функции [`open_connection()`](https://python-all.ru/3.15/library/asyncio-stream.html#asyncio.open_connection):418419```python420import asyncio421import socket422423async def wait_for_data():424 # Получить ссылку на текущий цикл событий, так как425 # мы хотим получить доступ к низкоуровневым API.426 loop = asyncio.get_running_loop()427428 # Создать пару соединённых сокетов.429 rsock, wsock = socket.socketpair()430431 # Зарегистрировать открытый сокет для ожидания данных.432 reader, writer = await asyncio.open_connection(sock=rsock)433434 # Симулировать приём данных из сети435 loop.call_soon(wsock.send, 'abc'.encode())436437 # Ожидать данные438 data = await reader.read(100)439440 # Данные получены, всё готово: закрыть сокет441 print("Received:", data.decode())442 writer.close()443 await writer.wait_closed()444445 # Закрыть второй сокет446 wsock.close()447448asyncio.run(wait_for_data())449```450451> **См. также**452>453> Пример [регистрация открытого сокета для ожидания данных с использованием протокола](https://python-all.ru/3.15/library/asyncio-protocol.html#asyncio-example-create-connection) использует низкоуровневый протокол и метод [`loop.create_connection()`](https://python-all.ru/3.15/library/asyncio-eventloop.html#asyncio.loop.create_connection).454>455> Пример [наблюдения за файловым дескриптором на предмет событий чтения](https://python-all.ru/3.15/library/asyncio-eventloop.html#asyncio-example-watch-fd) использует низкоуровневый метод [`loop.add_reader()`](https://python-all.ru/3.15/library/asyncio-eventloop.html#asyncio.loop.add_reader) для наблюдения за файловым дескриптором.456