asyncio-stream.md
1> **Источник:** https://python-all.ru/3.8/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.8/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.8/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)`4546Устанавливает сетевое соединение и возвращает пару объектов `(reader, writer)`.4748Возвращаемые объекты *reader* и *writer* являются экземплярами классов [`StreamReader`](https://python-all.ru/3.8/library/asyncio-stream.html#asyncio.StreamReader) и [`StreamWriter`](https://python-all.ru/3.8/library/asyncio-stream.html#asyncio.StreamWriter).4950Аргумент *loop* необязателен и всегда определяется автоматически при ожидании этой функции из корутины.5152Параметр *limit* определяет ограничение размера буфера, используемого возвращаемым экземпляром [`StreamReader`](https://python-all.ru/3.8/library/asyncio-stream.html#asyncio.StreamReader). По умолчанию *limit* установлен в 64 КиБ.5354Остальные аргументы передаются напрямую в [`loop.create_connection()`](https://python-all.ru/3.8/library/asyncio-eventloop.html#asyncio.loop.create_connection).5556Новое в версии 3.7: параметр *ssl\_handshake\_timeout*.5758#### `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)`5960Запускает сокет-сервер.6162Колбэк *client\_connected\_cb* вызывается при каждом установлении нового подключения клиента. Он получает пару `(reader, writer)` в качестве двух аргументов – экземпляры классов [`StreamReader`](https://python-all.ru/3.8/library/asyncio-stream.html#asyncio.StreamReader) и [`StreamWriter`](https://python-all.ru/3.8/library/asyncio-stream.html#asyncio.StreamWriter).6364*client\_connected\_cb* может быть обычным вызываемым объектом или [корутинной функцией](https://python-all.ru/3.8/library/asyncio-task.html#coroutine); если это корутинная функция, она будет автоматически запланирована как [`Task`](https://python-all.ru/3.8/library/asyncio-task.html#asyncio.Task).6566Аргумент *loop* необязателен и всегда определяется автоматически при ожидании этого метода из корутины.6768Параметр *limit* определяет ограничение размера буфера, используемого возвращаемым экземпляром [`StreamReader`](https://python-all.ru/3.8/library/asyncio-stream.html#asyncio.StreamReader). По умолчанию *limit* установлен в 64 КиБ.6970Остальные аргументы передаются напрямую в [`loop.create_server()`](https://python-all.ru/3.8/library/asyncio-eventloop.html#asyncio.loop.create_server).7172Новое в версии 3.7: параметры *ssl\_handshake\_timeout* и *start\_serving*.7374Unix-сокеты7576#### `coroutine asyncio.open_unix_connection(path=None, *, loop=None, limit=None, ssl=None, sock=None, server_hostname=None, ssl_handshake_timeout=None)`7778Устанавливает соединение через Unix-сокет и возвращает пару `(reader, writer)`.7980Аналогично [`open_connection()`](https://python-all.ru/3.8/library/asyncio-stream.html#asyncio.open_connection), но работает с Unix-сокетами.8182См. также документацию [`loop.create_unix_connection()`](https://python-all.ru/3.8/library/asyncio-eventloop.html#asyncio.loop.create_unix_connection).8384[Доступность](https://python-all.ru/3.8/library/intro.html#availability): Unix.8586Новое в версии 3.7: параметр *ssl\_handshake\_timeout*.8788Изменено в версии 3.7: Параметр *path* теперь может быть [объектом, подобным пути](https://python-all.ru/3.8/glossary.html#term-path-like-object)8990#### `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)`9192Запуск сервера Unix-сокетов.9394Аналогично [`start_server()`](https://python-all.ru/3.8/library/asyncio-stream.html#asyncio.start_server), но работает с Unix-сокетами.9596См. также документацию [`loop.create_unix_server()`](https://python-all.ru/3.8/library/asyncio-eventloop.html#asyncio.loop.create_unix_server).9798[Доступность](https://python-all.ru/3.8/library/intro.html#availability): Unix.99100Новое в версии 3.7: параметры *ssl\_handshake\_timeout* и *start\_serving*.101102Изменено в версии 3.7: Параметр *path* теперь может быть [path-подобным объектом](https://python-all.ru/3.8/glossary.html#term-path-like-object).103104## StreamReader105106#### `class asyncio.StreamReader`107108Представляет объект чтения, предоставляющий API для чтения данных из потока ввода-вывода.109110Не рекомендуется создавать объекты *StreamReader* напрямую; вместо этого используйте [`open_connection()`](https://python-all.ru/3.8/library/asyncio-stream.html#asyncio.open_connection) и [`start_server()`](https://python-all.ru/3.8/library/asyncio-stream.html#asyncio.start_server).111112#### `coroutine read(n=-1)`113114Читает до *n* байт. Если *n* не указан или равен `-1`, читает до EOF и возвращает все прочитанные байты.115116Если получен EOF и внутренний буфер пуст, возвращает пустой объект `bytes`.117118#### `coroutine readline()`119120Читает одну строку, где «строка» – это последовательность байтов, заканчивающаяся `\n`.121122Если получен EOF и `\n` не найден, метод возвращает частично прочитанные данные.123124Если получен EOF и внутренний буфер пуст, возвращается пустой объект `bytes`.125126#### `coroutine readexactly(n)`127128Прочитать ровно *n* байт.129130Возбуждается [`IncompleteReadError`](https://python-all.ru/3.8/library/asyncio-exceptions.html#asyncio.IncompleteReadError), если EOF достигнут до того, как прочитано *n* байт. Используйте атрибут [`IncompleteReadError.partial`](https://python-all.ru/3.8/library/asyncio-exceptions.html#asyncio.IncompleteReadError.partial), чтобы получить частично прочитанные данные.131132#### `coroutine readuntil(separator=b'\n')`133134Читает данные из потока до тех пор, пока не будет найден *separator*.135136В случае успеха данные и разделитель удаляются из внутреннего буфера (потребляются). Возвращаемые данные включают разделитель в конце.137138Если объем прочитанных данных превышает настроенный лимит потока, возбуждается исключение [`LimitOverrunError`](https://python-all.ru/3.8/library/asyncio-exceptions.html#asyncio.LimitOverrunError), а данные остаются во внутреннем буфере и могут быть прочитаны снова.139140Если EOF достигнут до того, как найден полный разделитель, возбуждается исключение [`IncompleteReadError`](https://python-all.ru/3.8/library/asyncio-exceptions.html#asyncio.IncompleteReadError), и внутренний буфер сбрасывается. Атрибут [`IncompleteReadError.partial`](https://python-all.ru/3.8/library/asyncio-exceptions.html#asyncio.IncompleteReadError.partial) может содержать часть разделителя.141142Новое в версии 3.5.2.143144#### `at_eof()`145146Возвращает `True`, если буфер пуст и был вызван `feed_eof()`.147148## StreamWriter149150#### `class asyncio.StreamWriter`151152Представляет объект-писатель, предоставляющий API для записи данных в поток ввода-вывода.153154Не рекомендуется создавать объекты *StreamWriter* напрямую; вместо этого используйте [`open_connection()`](https://python-all.ru/3.8/library/asyncio-stream.html#asyncio.open_connection) и [`start_server()`](https://python-all.ru/3.8/library/asyncio-stream.html#asyncio.start_server).155156#### `write(data)`157158Метод пытается немедленно записать *data* в нижележащий сокет. Если это не удаётся, данные помещаются во внутренний буфер записи до тех пор, пока их нельзя будет отправить.159160Метод следует использовать вместе с методом `drain()`:161162```python163stream.write(data)164await stream.drain()165```166167#### `writelines(data)`168169Метод немедленно записывает список (или любой итерируемый объект) байт в нижележащий сокет. Если это не удаётся, данные помещаются во внутренний буфер записи до тех пор, пока их нельзя будет отправить.170171Метод следует использовать вместе с методом `drain()`:172173```python174stream.writelines(lines)175await stream.drain()176```177178#### `close()`179180Метод закрывает поток и нижележащий сокет.181182Метод следует использовать вместе с методом `wait_closed()`:183184```python185stream.close()186await stream.wait_closed()187```188189#### `can_write_eof()`190191Возвращает `True`, если нижележащий транспорт поддерживает метод [`write_eof()`](https://python-all.ru/3.8/library/asyncio-stream.html#asyncio.StreamWriter.write_eof), и `False` в противном случае.192193#### `write_eof()`194195Закрывает конец потока для записи после сброса буферизованных данных записи.196197#### `transport`198199Возвращает базовый транспорт asyncio.200201#### `get_extra_info(name, default=None)`202203Предоставляет доступ к дополнительной информации о транспорте; подробнее см. [`BaseTransport.get_extra_info()`](https://python-all.ru/3.8/library/asyncio-protocol.html#asyncio.BaseTransport.get_extra_info).204205#### `coroutine drain()`206207Ожидает, когда можно будет возобновить запись в поток данных. Пример:208209```python210writer.write(data)211await writer.drain()212```213214Это метод управления потоком, который взаимодействует с базовым буфером записи ввода-вывода. Когда размер буфера достигает верхней границы, *drain()* блокируется, пока размер буфера не уменьшится до нижней границы, после чего запись можно возобновить. Если ждать нечего, [`drain()`](https://python-all.ru/3.8/library/asyncio-stream.html#asyncio.StreamWriter.drain) возвращает управление немедленно.215216#### `is_closing()`217218Возвращает `True`, если поток данных закрыт или находится в процессе закрытия.219220Добавлено в версии 3.7.221222#### `coroutine wait_closed()`223224Ожидает закрытия потока данных.225226Должен вызываться после [`close()`](https://python-all.ru/3.8/library/asyncio-stream.html#asyncio.StreamWriter.close), чтобы дождаться закрытия нижележащего соединения.227228Добавлено в версии 3.7.229230## Примеры231232### TCP-эхо-клиент с использованием потоков данных233234TCP-эхо-клиент с использованием функции [`asyncio.open_connection()`](https://python-all.ru/3.8/library/asyncio-stream.html#asyncio.open_connection):235236```python237import asyncio238239async def tcp_echo_client(message):240 reader, writer = await asyncio.open_connection(241 '127.0.0.1', 8888)242243 print(f'Send: {message!r}')244 writer.write(message.encode())245246 data = await reader.read(100)247 print(f'Received: {data.decode()!r}')248249 print('Close the connection')250 writer.close()251252asyncio.run(tcp_echo_client('Hello World!'))253```254255> **См. также**256>257> Пример [протокол TCP-эхо-клиента](https://python-all.ru/3.8/library/asyncio-protocol.html#asyncio-example-tcp-echo-client-protocol) использует низкоуровневый метод [`loop.create_connection()`](https://python-all.ru/3.8/library/asyncio-eventloop.html#asyncio.loop.create_connection).258259### TCP-эхо-сервер с использованием потоков данных260261TCP-эхо-сервер с использованием функции [`asyncio.start_server()`](https://python-all.ru/3.8/library/asyncio-stream.html#asyncio.start_server):262263```python264import asyncio265266async def handle_echo(reader, writer):267 data = await reader.read(100)268 message = data.decode()269 addr = writer.get_extra_info('peername')270271 print(f"Received {message!r} from {addr!r}")272273 print(f"Send: {message!r}")274 writer.write(data)275 await writer.drain()276277 print("Close the connection")278 writer.close()279280async def main():281 server = await asyncio.start_server(282 handle_echo, '127.0.0.1', 8888)283284 addr = server.sockets[0].getsockname()285 print(f'Serving on {addr}')286287 async with server:288 await server.serve_forever()289290asyncio.run(main())291```292293> **См. также**294>295> Пример [протокол TCP-эхо-сервера](https://python-all.ru/3.8/library/asyncio-protocol.html#asyncio-example-tcp-echo-server-protocol) использует метод [`loop.create_server()`](https://python-all.ru/3.8/library/asyncio-eventloop.html#asyncio.loop.create_server).296297### Получение HTTP-заголовков298299Простой пример получения HTTP-заголовков URL, переданного в командной строке:300301```python302import asyncio303import urllib.parse304import sys305306async def print_http_headers(url):307 url = urllib.parse.urlsplit(url)308 if url.scheme == 'https':309 reader, writer = await asyncio.open_connection(310 url.hostname, 443, ssl=True)311 else:312 reader, writer = await asyncio.open_connection(313 url.hostname, 80)314315 query = (316 f"HEAD {url.path or '/'} HTTP/1.0\r\n"317 f"Host: {url.hostname}\r\n"318 f"\r\n"319 )320321 writer.write(query.encode('latin-1'))322 while True:323 line = await reader.readline()324 if not line:325 break326327 line = line.decode('latin1').rstrip()328 if line:329 print(f'HTTP header> {line}')330331 # Игнорировать тело, закрыть сокет332 writer.close()333334url = sys.argv[1]335asyncio.run(print_http_headers(url))336```337338Использование:339340```python341python example.py http://example.com/path/page.html342```343344или с HTTPS:345346```python347python example.py https://example.com/path/page.html348```349350### Регистрация открытого сокета для ожидания данных с использованием потоков данных351352Корутина, ожидающая получения данных сокетом с помощью функции [`open_connection()`](https://python-all.ru/3.8/library/asyncio-stream.html#asyncio.open_connection):353354```python355import asyncio356import socket357358async def wait_for_data():359 # Получить ссылку на текущий цикл событий, так как360 # мы хотим получить доступ к низкоуровневым API.361 loop = asyncio.get_running_loop()362363 # Создать пару соединённых сокетов.364 rsock, wsock = socket.socketpair()365366 # Зарегистрировать открытый сокет для ожидания данных.367 reader, writer = await asyncio.open_connection(sock=rsock)368369 # Симулировать приём данных из сети370 loop.call_soon(wsock.send, 'abc'.encode())371372 # Ожидать данные373 data = await reader.read(100)374375 # Данные получены, всё готово: закрыть сокет376 print("Received:", data.decode())377 writer.close()378379 # Закрыть второй сокет380 wsock.close()381382asyncio.run(wait_for_data())383```384385> **См. также**386>387> Пример [регистрация открытого сокета для ожидания данных с использованием протокола](https://python-all.ru/3.8/library/asyncio-protocol.html#asyncio-example-create-connection) использует низкоуровневый протокол и метод [`loop.create_connection()`](https://python-all.ru/3.8/library/asyncio-eventloop.html#asyncio.loop.create_connection).388>389> Пример [наблюдения за файловым дескриптором на предмет событий чтения](https://python-all.ru/3.8/library/asyncio-eventloop.html#asyncio-example-watch-fd) использует низкоуровневый метод [`loop.add_reader()`](https://python-all.ru/3.8/library/asyncio-eventloop.html#asyncio.loop.add_reader) для наблюдения за файловым дескриптором.390