asyncio-stream.md
1> **Источник:** https://python-all.ru/3.5/library/asyncio-stream.html2>3> «Документация Python на русском» – неофициальный перевод официальной документации Python: версии от 2.6 до 3.16, полнотекстовый поиск, английский оригинал рядом с переводом. Эта Markdown-версия страницы предназначена для работы с LLM: вставьте её в ChatGPT, Claude или Cursor.45---67# 18.5.5. Потоки данных (API на основе корутин)89## 18.5.5.1. Функции потоков данных1011> **Примечание**12>13> Функции верхнего уровня этого модуля – это лишь удобные обёртки; в них нет ничего особенного, и если они делают не совсем то, что вам нужно, можно просто скопировать их код.1415#### `coroutine asyncio.open_connection(host=None, port=None, *, loop=None, limit=None, **kwds)`1617Обёртка для [`create_connection()`](https://python-all.ru/3.5/library/asyncio-eventloop.html#asyncio.AbstractEventLoop.create_connection), возвращающая пару (reader, writer).1819Возвращаемый reader является экземпляром [`StreamReader`](https://python-all.ru/3.5/library/asyncio-stream.html#asyncio.StreamReader); writer – экземпляром [`StreamWriter`](https://python-all.ru/3.5/library/asyncio-stream.html#asyncio.StreamWriter).2021Аргументы совпадают с обычными аргументами [`AbstractEventLoop.create_connection()`](https://python-all.ru/3.5/library/asyncio-eventloop.html#asyncio.AbstractEventLoop.create_connection), за исключением *protocol\_factory*; наиболее распространёнными являются позиционные аргументы host и port, за которыми могут следовать различные необязательные именованные аргументы.2223Дополнительные необязательные именованные аргументы: *loop* (для указания используемого экземпляра цикла событий) и *limit* (для установки лимита буфера, передаваемого в [`StreamReader`](https://python-all.ru/3.5/library/asyncio-stream.html#asyncio.StreamReader)).2425Эта функция – [корутина](https://python-all.ru/3.5/library/asyncio-task.html#coroutine).2627#### `coroutine asyncio.start_server(client_connected_cb, host=None, port=None, *, loop=None, limit=None, **kwds)`2829Запускает сокет-сервер с колбэком для каждого подключившегося клиента. Возвращаемое значение такое же, как у [`create_server()`](https://python-all.ru/3.5/library/asyncio-eventloop.html#asyncio.AbstractEventLoop.create_server).3031Параметр *client\_connected\_cb* вызывается с двумя параметрами: *client\_reader* и *client\_writer*. *client\_reader* является объектом [`StreamReader`](https://python-all.ru/3.5/library/asyncio-stream.html#asyncio.StreamReader), а *client\_writer* – объектом [`StreamWriter`](https://python-all.ru/3.5/library/asyncio-stream.html#asyncio.StreamWriter). Параметр *client\_connected\_cb* может быть как обычной функцией-колбэком, так и [корутинной функцией](https://python-all.ru/3.5/library/asyncio-task.html#coroutine); если это корутинная функция, она будет автоматически преобразована в [`Task`](https://python-all.ru/3.5/library/asyncio-task.html#asyncio.Task).3233Остальные аргументы – это все обычные аргументы [`create_server()`](https://python-all.ru/3.5/library/asyncio-eventloop.html#asyncio.AbstractEventLoop.create_server), за исключением *protocol\_factory*; наиболее распространёнными являются позиционные аргументы *host* и *port*, за которыми могут следовать различные необязательные именованные аргументы.3435Дополнительные необязательные именованные аргументы: *loop* (для указания используемого экземпляра цикла событий) и *limit* (для установки лимита буфера, передаваемого в [`StreamReader`](https://python-all.ru/3.5/library/asyncio-stream.html#asyncio.StreamReader)).3637Эта функция – [корутина](https://python-all.ru/3.5/library/asyncio-task.html#coroutine).3839#### `coroutine asyncio.open_unix_connection(path=None, *, loop=None, limit=None, **kwds)`4041Обёртка для [`create_unix_connection()`](https://python-all.ru/3.5/library/asyncio-eventloop.html#asyncio.AbstractEventLoop.create_unix_connection), возвращающая пару (reader, writer).4243См. [`open_connection()`](https://python-all.ru/3.5/library/asyncio-stream.html#asyncio.open_connection) для получения сведений о возвращаемом значении и других подробностях.4445Эта функция – [корутина](https://python-all.ru/3.5/library/asyncio-task.html#coroutine).4647Доступность: UNIX.4849#### `coroutine asyncio.start_unix_server(client_connected_cb, path=None, *, loop=None, limit=None, **kwds)`5051Запускает сервер UNIX Domain Socket с колбэком для каждого подключившегося клиента.5253См. [`start_server()`](https://python-all.ru/3.5/library/asyncio-stream.html#asyncio.start_server) для получения сведений о возвращаемом значении и других подробностях.5455Эта функция – [корутина](https://python-all.ru/3.5/library/asyncio-task.html#coroutine).5657Доступность: UNIX.5859## 18.5.5.2. StreamReader6061#### `class asyncio.StreamReader(limit=None, loop=None)`6263This class is [не является потокобезопасным](https://python-all.ru/3.5/library/asyncio-dev.html#asyncio-multithreading).6465#### `exception()`6667Получить исключение.6869#### `feed_eof()`7071Подтверждает конец файла (EOF).7273#### `feed_data(data)`7475Подаёт байты *data* во внутренний буфер. Любые операции, ожидающие данные, будут возобновлены.7677#### `set_exception(exc)`7879Устанавливает исключение.8081#### `set_transport(transport)`8283Устанавливает транспорт.8485#### `coroutine read(n=-1)`8687Читает до *n* байт. Если *n* не указан или равен `-1`, читает до EOF и возвращает все прочитанные байты.8889Если получен EOF и внутренний буфер пуст, возвращает пустой объект `bytes`.9091Этот метод является [корутиной](https://python-all.ru/3.5/library/asyncio-task.html#coroutine).9293#### `coroutine readline()`9495Читает одну строку, где «строка» – это последовательность байтов, заканчивающаяся `\n`.9697Если получен EOF, а `\n` не найден, метод вернёт частично прочитанные байты.9899Если получен EOF и внутренний буфер пуст, возвращает пустой объект `bytes`.100101Этот метод является [корутиной](https://python-all.ru/3.5/library/asyncio-task.html#coroutine).102103#### `coroutine readexactly(n)`104105Читает ровно *n* байт. Вызывает [`IncompleteReadError`](https://python-all.ru/3.5/library/asyncio-stream.html#asyncio.IncompleteReadError), если конец потока достигнут до того, как можно прочитать *n*. Атрибут [`IncompleteReadError.partial`](https://python-all.ru/3.5/library/asyncio-stream.html#asyncio.IncompleteReadError.partial) исключения содержит частично прочитанные байты.106107Этот метод является [корутиной](https://python-all.ru/3.5/library/asyncio-task.html#coroutine).108109#### `coroutine readuntil(separator=b'\n')`110111Читает данные из потока, пока не будет найден `separator`.112113В случае успеха данные и разделитель удаляются из внутреннего буфера (потребляются). Возвращаемые данные включают разделитель в конце.114115Настроенный лимит потока используется для проверки результата. Лимит определяет максимальную длину возвращаемых данных, не включая разделитель.116117Если возникает EOF, а полный разделитель всё ещё не найден, будет вызвано исключение [`IncompleteReadError`](https://python-all.ru/3.5/library/asyncio-stream.html#asyncio.IncompleteReadError), и внутренний буфер будет сброшен. Атрибут [`IncompleteReadError.partial`](https://python-all.ru/3.5/library/asyncio-stream.html#asyncio.IncompleteReadError.partial) может содержать часть разделителя.118119Если данные не могут быть прочитаны из-за превышения лимита, будет вызвано исключение [`LimitOverrunError`](https://python-all.ru/3.5/library/asyncio-stream.html#asyncio.LimitOverrunError), а данные останутся во внутреннем буфере, чтобы их можно было прочитать снова.120121Новое в версии 3.5.2.122123#### `at_eof()`124125Возвращает `True`, если буфер пуст и был вызван [`feed_eof()`](https://python-all.ru/3.5/library/asyncio-stream.html#asyncio.StreamReader.feed_eof).126127## 18.5.5.3. StreamWriter128129#### `class asyncio.StreamWriter(transport, protocol, reader, loop)`130131Оборачивает Transport.132133Этот класс предоставляет [`write()`](https://python-all.ru/3.5/library/asyncio-stream.html#asyncio.StreamWriter.write), [`writelines()`](https://python-all.ru/3.5/library/asyncio-stream.html#asyncio.StreamWriter.writelines), [`can_write_eof()`](https://python-all.ru/3.5/library/asyncio-stream.html#asyncio.StreamWriter.can_write_eof), [`write_eof()`](https://python-all.ru/3.5/library/asyncio-stream.html#asyncio.StreamWriter.write_eof), [`get_extra_info()`](https://python-all.ru/3.5/library/asyncio-stream.html#asyncio.StreamWriter.get_extra_info) и [`close()`](https://python-all.ru/3.5/library/asyncio-stream.html#asyncio.StreamWriter.close). Он добавляет [`drain()`](https://python-all.ru/3.5/library/asyncio-stream.html#asyncio.StreamWriter.drain), который возвращает необязательный [`Future`](https://python-all.ru/3.5/library/asyncio-task.html#asyncio.Future), на котором можно ожидать управления потоком. Также добавляется атрибут транспорта, который ссылается непосредственно на `Transport`.134135This class is [не является потокобезопасным](https://python-all.ru/3.5/library/asyncio-dev.html#asyncio-multithreading).136137#### `transport`138139Транспорт.140141#### `can_write_eof()`142143Возвращает [`True`](https://python-all.ru/3.5/library/constants.html#True), если транспорт поддерживает [`write_eof()`](https://python-all.ru/3.5/library/asyncio-stream.html#asyncio.StreamWriter.write_eof), [`False`](https://python-all.ru/3.5/library/constants.html#False) – в противном случае. См. [`WriteTransport.can_write_eof()`](https://python-all.ru/3.5/library/asyncio-protocol.html#asyncio.WriteTransport.can_write_eof).144145#### `close()`146147Закрывает транспорт: см. [`BaseTransport.close()`](https://python-all.ru/3.5/library/asyncio-protocol.html#asyncio.BaseTransport.close).148149#### `coroutine drain()`150151Даёт возможность сбросить буфер записи нижележащего транспорта.152153Предполагаемое использование – записать:154155```python156w.write(data)157yield from w.drain()158```159160Когда размер буфера транспорта достигает верхнего порога (протокол приостанавливается), блокируется до тех пор, пока размер буфера не уменьшится до нижнего порога и протокол не будет возобновлён. Когда ждать нечего, yield-from продолжается немедленно.161162Передача управления через [`drain()`](https://python-all.ru/3.5/library/asyncio-stream.html#asyncio.StreamWriter.drain) даёт циклу событий возможность запланировать операцию записи и сбросить буфер. Это следует использовать особенно тогда, когда в транспорт записывается, возможно, большой объём данных, и корутина не передаёт управление между вызовами [`write()`](https://python-all.ru/3.5/library/asyncio-stream.html#asyncio.StreamWriter.write).163164Этот метод является [корутиной](https://python-all.ru/3.5/library/asyncio-task.html#coroutine).165166#### `get_extra_info(name, default=None)`167168Возвращает необязательную информацию о транспорте: см. [`BaseTransport.get_extra_info()`](https://python-all.ru/3.5/library/asyncio-protocol.html#asyncio.BaseTransport.get_extra_info).169170#### `write(data)`171172Записать некоторые *data* байтов в транспорт: см. [`WriteTransport.write()`](https://python-all.ru/3.5/library/asyncio-protocol.html#asyncio.WriteTransport.write).173174#### `writelines(data)`175176Записать список (или любой итерируемый объект) байтов в транспорт: см. [`WriteTransport.writelines()`](https://python-all.ru/3.5/library/asyncio-protocol.html#asyncio.WriteTransport.writelines).177178#### `write_eof()`179180Закрыть конец записи транспорта после сброса буферизованных данных: см. [`WriteTransport.write_eof()`](https://python-all.ru/3.5/library/asyncio-protocol.html#asyncio.WriteTransport.write_eof).181182## 18.5.5.4. StreamReaderProtocol183184#### `class asyncio.StreamReaderProtocol(stream_reader, client_connected_cb=None, loop=None)`185186Вспомогательный класс для адаптации между [`Protocol`](https://python-all.ru/3.5/library/asyncio-protocol.html#asyncio.Protocol) и [`StreamReader`](https://python-all.ru/3.5/library/asyncio-stream.html#asyncio.StreamReader). Подкласс [`Protocol`](https://python-all.ru/3.5/library/asyncio-protocol.html#asyncio.Protocol).187188*stream\_reader* является экземпляром [`StreamReader`](https://python-all.ru/3.5/library/asyncio-stream.html#asyncio.StreamReader), *client\_connected\_cb* – необязательная функция, вызываемая с (stream\_reader, stream\_writer) при установлении соединения, *loop* – используемый экземпляр цикла событий.189190(Это вспомогательный класс вместо того, чтобы делать сам [`StreamReader`](https://python-all.ru/3.5/library/asyncio-stream.html#asyncio.StreamReader) подклассом [`Protocol`](https://python-all.ru/3.5/library/asyncio-protocol.html#asyncio.Protocol), так как [`StreamReader`](https://python-all.ru/3.5/library/asyncio-stream.html#asyncio.StreamReader) имеет другие потенциальные применения, и чтобы предотвратить случайный вызов пользователем [`StreamReader`](https://python-all.ru/3.5/library/asyncio-stream.html#asyncio.StreamReader) неподходящих методов протокола.)191192## 18.5.5.5. IncompleteReadError193194#### `exception asyncio.IncompleteReadError`195196> Ошибка неполного чтения, подкласс197>198> [`EOFError`](https://python-all.ru/3.5/library/exceptions.html#EOFError)199>200> .201202#### `expected`203204Общее количество ожидаемых байтов ([`int`](https://python-all.ru/3.5/library/functions.html#int)).205206#### `partial`207208Прочитанная строка байтов до достижения конца потока ([`bytes`](https://python-all.ru/3.5/library/functions.html#bytes)).209210## 18.5.5.6. LimitOverrunError211212#### `exception asyncio.LimitOverrunError`213214Достигнут предел буфера во время поиска разделителя.215216#### `consumed`217218Общее количество байтов для обработки.219220## 18.5.5.7. Примеры потоков данных221222### 18.5.5.7.1. TCP-клиент эхо-сервера с использованием потоков данных223224TCP-эхо-клиент с использованием функции [`asyncio.open_connection()`](https://python-all.ru/3.5/library/asyncio-stream.html#asyncio.open_connection):225226```python227import asyncio228229@asyncio.coroutine230def tcp_echo_client(message, loop):231 reader, writer = yield from asyncio.open_connection('127.0.0.1', 8888,232 loop=loop)233234 print('Send: %r' % message)235 writer.write(message.encode())236237 data = yield from reader.read(100)238 print('Received: %r' % data.decode())239240 print('Close the socket')241 writer.close()242243message = 'Hello World!'244loop = asyncio.get_event_loop()245loop.run_until_complete(tcp_echo_client(message, loop))246loop.close()247```248249> **См. также**250>251> Пример [протокола TCP-эхо-клиента](https://python-all.ru/3.5/library/asyncio-protocol.html#asyncio-tcp-echo-client-protocol) использует метод [`AbstractEventLoop.create_connection()`](https://python-all.ru/3.5/library/asyncio-eventloop.html#asyncio.AbstractEventLoop.create_connection).252253### 18.5.5.7.2. TCP-эхо-сервер с использованием потоков данных254255TCP-эхо-сервер с использованием функции [`asyncio.start_server()`](https://python-all.ru/3.5/library/asyncio-stream.html#asyncio.start_server):256257```python258import asyncio259260@asyncio.coroutine261def handle_echo(reader, writer):262 data = yield from reader.read(100)263 message = data.decode()264 addr = writer.get_extra_info('peername')265 print("Received %r from %r" % (message, addr))266267 print("Send: %r" % message)268 writer.write(data)269 yield from writer.drain()270271 print("Close the client socket")272 writer.close()273274loop = asyncio.get_event_loop()275coro = asyncio.start_server(handle_echo, '127.0.0.1', 8888, loop=loop)276server = loop.run_until_complete(coro)277278# Обслуживать запросы до нажатия Ctrl+C279print('Serving on {}'.format(server.sockets[0].getsockname()))280try:281 loop.run_forever()282except KeyboardInterrupt:283 pass284285# Закрыть сервер286server.close()287loop.run_until_complete(server.wait_closed())288loop.close()289```290291> **См. также**292>293> Пример [протокол TCP-эхо-сервера](https://python-all.ru/3.5/library/asyncio-protocol.html#asyncio-tcp-echo-server-protocol) использует метод [`AbstractEventLoop.create_server()`](https://python-all.ru/3.5/library/asyncio-eventloop.html#asyncio.AbstractEventLoop.create_server).294295### 18.5.5.7.3. Получение HTTP-заголовков296297Простой пример получения HTTP-заголовков URL, переданного в командной строке:298299```python300import asyncio301import urllib.parse302import sys303304@asyncio.coroutine305def print_http_headers(url):306 url = urllib.parse.urlsplit(url)307 if url.scheme == 'https':308 connect = asyncio.open_connection(url.hostname, 443, ssl=True)309 else:310 connect = asyncio.open_connection(url.hostname, 80)311 reader, writer = yield from connect312 query = ('HEAD {path} HTTP/1.0\r\n'313 'Host: {hostname}\r\n'314 '\r\n').format(path=url.path or '/', hostname=url.hostname)315 writer.write(query.encode('latin-1'))316 while True:317 line = yield from reader.readline()318 if not line:319 break320 line = line.decode('latin1').rstrip()321 if line:322 print('HTTP header> %s' % line)323324 # Игнорировать тело, закрыть сокет325 writer.close()326327url = sys.argv[1]328loop = asyncio.get_event_loop()329task = asyncio.ensure_future(print_http_headers(url))330loop.run_until_complete(task)331loop.close()332```333334Использование:335336```python337python example.py http://example.com/path/page.html338```339340или с HTTPS:341342```python343python example.py https://example.com/path/page.html344```345346### 18.5.5.7.4. Регистрация открытого сокета для ожидания данных с помощью потоков данных347348Корутина, ожидающая получения данных сокетом с помощью функции [`open_connection()`](https://python-all.ru/3.5/library/asyncio-stream.html#asyncio.open_connection):349350```python351import asyncio352try:353 from socket import socketpair354except ImportError:355 from asyncio.windows_utils import socketpair356357@asyncio.coroutine358def wait_for_data(loop):359 # Создаём пару соединённых сокетов360 rsock, wsock = socketpair()361362 # Зарегистрировать открытый сокет для ожидания данных363 reader, writer = yield from asyncio.open_connection(sock=rsock, loop=loop)364365 # Симулировать приём данных из сети366 loop.call_soon(wsock.send, 'abc'.encode())367368 # Ожидать данные369 data = yield from reader.read(100)370371 # Данные получены, всё готово: закрыть сокет372 print("Received:", data.decode())373 writer.close()374375 # Закрыть второй сокет376 wsock.close()377378loop = asyncio.get_event_loop()379loop.run_until_complete(wait_for_data(loop))380loop.close()381```382383> **См. также**384>385> Пример [регистрации открытого сокета для ожидания данных с помощью протокола](https://python-all.ru/3.5/library/asyncio-protocol.html#asyncio-register-socket) использует низкоуровневый протокол, созданный методом [`AbstractEventLoop.create_connection()`](https://python-all.ru/3.5/library/asyncio-eventloop.html#asyncio.AbstractEventLoop.create_connection).386>387> Пример [наблюдения за файловым дескриптором на предмет событий чтения](https://python-all.ru/3.5/library/asyncio-eventloop.html#asyncio-watch-read-event) использует низкоуровневый метод [`AbstractEventLoop.add_reader()`](https://python-all.ru/3.5/library/asyncio-eventloop.html#asyncio.AbstractEventLoop.add_reader) для регистрации файлового дескриптора сокета.388