Spaces:
Running on Zero
Running on Zero
| ::: currentmodule | |
| asyncio | |
| ::: | |
| # Streams {#asyncio-streams} | |
| **Source code:** `Lib/asyncio/streams.py`{.interpreted-text role="source"} | |
| ------------------------------------------------------------------------ | |
| Streams are high-level async/await-ready primitives to work with network connections. Streams allow sending and receiving data without using callbacks or low-level protocols and transports. | |
| ::: {#asyncio_example_stream} | |
| Here is an example of a TCP echo client written using asyncio streams: | |
| import asyncio | |
| async def tcp_echo_client(message): | |
| reader, writer = await asyncio.open_connection( | |
| '127.0.0.1', 8888) | |
| print(f'Send: {message!r}') | |
| writer.write(message.encode()) | |
| await writer.drain() | |
| data = await reader.read(100) | |
| print(f'Received: {data.decode()!r}') | |
| print('Close the connection') | |
| writer.close() | |
| await writer.wait_closed() | |
| asyncio.run(tcp_echo_client('Hello World!')) | |
| ::: | |
| See also the [Examples](#examples) section below. | |
| **Stream Functions** | |
| The following top-level asyncio functions can be used to create and work with streams: | |
| ::::::::: {.function async=""} | |
| 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) | |
| Establish a network connection and return a pair of `(reader, writer)` objects. | |
| The returned *reader* and *writer* objects are instances of `StreamReader`{.interpreted-text role="class"} and `StreamWriter`{.interpreted-text role="class"} classes. | |
| *limit* determines the buffer size limit used by the returned `StreamReader`{.interpreted-text role="class"} instance. By default the *limit* is set to 64 KiB. | |
| The rest of the arguments are passed directly to `loop.create_connection`{.interpreted-text role="meth"}. | |
| :::: note | |
| ::: title | |
| Note | |
| ::: | |
| The *sock* argument transfers ownership of the socket to the `StreamWriter`{.interpreted-text role="class"} created. To close the socket, call its `~asyncio.StreamWriter.close`{.interpreted-text role="meth"} method. | |
| :::: | |
| ::: versionchanged | |
| 3.7 Added the *ssl_handshake_timeout* parameter. | |
| ::: | |
| ::: versionchanged | |
| 3.8 Added the *happy_eyeballs_delay* and *interleave* parameters. | |
| ::: | |
| ::: versionchanged | |
| 3.10 Removed the *loop* parameter. | |
| ::: | |
| ::: versionchanged | |
| 3.11 Added the *ssl_shutdown_timeout* parameter. | |
| ::: | |
| ::::::::: | |
| ::::::::: {.function async=""} | |
| 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) | |
| Start a socket server. | |
| The *client_connected_cb* callback is called whenever a new client connection is established. It receives a `(reader, writer)` pair as two arguments, instances of the `StreamReader`{.interpreted-text role="class"} and `StreamWriter`{.interpreted-text role="class"} classes. | |
| *client_connected_cb* can be a plain callable or a `coroutine function <coroutine>`{.interpreted-text role="ref"}; if it is a coroutine function, it will be automatically scheduled as a `Task`{.interpreted-text role="class"}. | |
| *limit* determines the buffer size limit used by the returned `StreamReader`{.interpreted-text role="class"} instance. By default the *limit* is set to 64 KiB. | |
| The rest of the arguments are passed directly to `loop.create_server`{.interpreted-text role="meth"}. | |
| :::: note | |
| ::: title | |
| Note | |
| ::: | |
| The *sock* argument transfers ownership of the socket to the server created. To close the socket, call the server\'s `~asyncio.Server.close`{.interpreted-text role="meth"} method. | |
| :::: | |
| ::: versionchanged | |
| 3.7 Added the *ssl_handshake_timeout* and *start_serving* parameters. | |
| ::: | |
| ::: versionchanged | |
| 3.10 Removed the *loop* parameter. | |
| ::: | |
| ::: versionchanged | |
| 3.11 Added the *ssl_shutdown_timeout* parameter. | |
| ::: | |
| ::: versionchanged | |
| 3.13 Added the *keep_alive* parameter. | |
| ::: | |
| ::::::::: | |
| **Unix Sockets** | |
| ::::::::: {.function async=""} | |
| open_unix_connection(path=None, \*, limit=None, ssl=None, sock=None, server_hostname=None, ssl_handshake_timeout=None, ssl_shutdown_timeout=None) | |
| Establish a Unix socket connection and return a pair of `(reader, writer)`. | |
| Similar to `open_connection`{.interpreted-text role="func"} but operates on Unix sockets. | |
| See also the documentation of `loop.create_unix_connection`{.interpreted-text role="meth"}. | |
| :::: note | |
| ::: title | |
| Note | |
| ::: | |
| The *sock* argument transfers ownership of the socket to the `StreamWriter`{.interpreted-text role="class"} created. To close the socket, call its `~asyncio.StreamWriter.close`{.interpreted-text role="meth"} method. | |
| :::: | |
| ::: availability | |
| Unix. | |
| ::: | |
| ::: versionchanged | |
| 3.7 Added the *ssl_handshake_timeout* parameter. The *path* parameter can now be a `path-like object`{.interpreted-text role="term"} | |
| ::: | |
| ::: versionchanged | |
| 3.10 Removed the *loop* parameter. | |
| ::: | |
| ::: versionchanged | |
| 3.11 Added the *ssl_shutdown_timeout* parameter. | |
| ::: | |
| ::::::::: | |
| :::::::::: {.function async=""} | |
| 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) | |
| Start a Unix socket server. | |
| Similar to `start_server`{.interpreted-text role="func"} but works with Unix sockets. | |
| If *cleanup_socket* is true then the Unix socket will automatically be removed from the filesystem when the server is closed, unless the socket has been replaced after the server has been created. | |
| See also the documentation of `loop.create_unix_server`{.interpreted-text role="meth"}. | |
| :::: note | |
| ::: title | |
| Note | |
| ::: | |
| The *sock* argument transfers ownership of the socket to the server created. To close the socket, call the server\'s `~asyncio.Server.close`{.interpreted-text role="meth"} method. | |
| :::: | |
| ::: availability | |
| Unix. | |
| ::: | |
| ::: versionchanged | |
| 3.7 Added the *ssl_handshake_timeout* and *start_serving* parameters. The *path* parameter can now be a `path-like object`{.interpreted-text role="term"}. | |
| ::: | |
| ::: versionchanged | |
| 3.10 Removed the *loop* parameter. | |
| ::: | |
| ::: versionchanged | |
| 3.11 Added the *ssl_shutdown_timeout* parameter. | |
| ::: | |
| ::: versionchanged | |
| 3.13 Added the *cleanup_socket* parameter. | |
| ::: | |
| :::::::::: | |
| ## StreamReader | |
| ::::::::::: StreamReader | |
| Represents a reader object that provides APIs to read data from the IO stream. As an `asynchronous iterable`{.interpreted-text role="term"}, the object supports the `async for`{.interpreted-text role="keyword"} statement. | |
| It is not recommended to instantiate *StreamReader* objects directly; use `open_connection`{.interpreted-text role="func"} and `start_server`{.interpreted-text role="func"} instead. | |
| ::: method | |
| feed_eof() | |
| Acknowledge the EOF. | |
| ::: | |
| ::: {.method async=""} | |
| read(n=-1) | |
| Read up to *n* bytes from the stream. | |
| If *n* is not provided or set to `-1`, read until EOF, then return all read `bytes`{.interpreted-text role="class"}. If EOF was received and the internal buffer is empty, return an empty `bytes` object. | |
| If *n* is `0`, return an empty `bytes` object immediately. | |
| If *n* is positive, return at most *n* available `bytes` as soon as at least 1 byte is available in the internal buffer. If EOF is received before any byte is read, return an empty `bytes` object. | |
| ::: | |
| ::: {.method async=""} | |
| readline() | |
| Read one line, where \"line\" is a sequence of bytes ending with `\n`. | |
| If EOF is received and `\n` was not found, the method returns partially read data. | |
| If EOF is received and the internal buffer is empty, return an empty `bytes` object. | |
| ::: | |
| ::: {.method async=""} | |
| readexactly(n) | |
| Read exactly *n* bytes. | |
| Raise an `IncompleteReadError`{.interpreted-text role="exc"} if EOF is reached before *n* can be read. Use the `IncompleteReadError.partial`{.interpreted-text role="attr"} attribute to get the partially read data. | |
| ::: | |
| ::::: {.method async=""} | |
| readuntil(separator=b\'n\') | |
| Read data from the stream until *separator* is found. | |
| On success, the data and separator will be removed from the internal buffer (consumed). Returned data will include the separator at the end. | |
| If the amount of data read exceeds the configured stream limit, a `LimitOverrunError`{.interpreted-text role="exc"} exception is raised, and the data is left in the internal buffer and can be read again. | |
| If EOF is reached before the complete separator is found, an `IncompleteReadError`{.interpreted-text role="exc"} exception is raised, and the internal buffer is reset. The `IncompleteReadError.partial`{.interpreted-text role="attr"} attribute may contain a portion of the separator. | |
| The *separator* may also be a tuple of separators. In this case the return value will be the shortest possible that has any separator as the suffix. For the purposes of `LimitOverrunError`{.interpreted-text role="exc"}, the shortest possible separator is considered to be the one that matched. | |
| ::: versionadded | |
| 3.5.2 | |
| ::: | |
| ::: versionchanged | |
| 3.13 | |
| The *separator* parameter may now be a `tuple`{.interpreted-text role="class"} of separators. | |
| ::: | |
| ::::: | |
| ::: method | |
| at_eof() | |
| Return `True` if the buffer is empty and `feed_eof`{.interpreted-text role="meth"} was called. | |
| ::: | |
| ::::::::::: | |
| ## StreamWriter | |
| :::::::::::::::::: StreamWriter | |
| Represents a writer object that provides APIs to write data to the IO stream. | |
| It is not recommended to instantiate *StreamWriter* objects directly; use `open_connection`{.interpreted-text role="func"} and `start_server`{.interpreted-text role="func"} instead. | |
| ::: method | |
| write(data) | |
| The method attempts to write the *data* to the underlying socket immediately. If that fails, the data is queued in an internal write buffer until it can be sent. | |
| The *data* buffer should be a bytes, bytearray, or C-contiguous one-dimensional memoryview object. | |
| The method should be used along with the `drain()` method: | |
| stream.write(data) | |
| await stream.drain() | |
| ::: | |
| ::: method | |
| writelines(data) | |
| The method writes a list (or any iterable) of bytes to the underlying socket immediately. If that fails, the data is queued in an internal write buffer until it can be sent. | |
| The method should be used along with the `drain()` method: | |
| stream.writelines(lines) | |
| await stream.drain() | |
| ::: | |
| ::: method | |
| close() | |
| The method closes the stream and the underlying socket. | |
| The method should be used, though not mandatory, along with the `wait_closed()` method: | |
| stream.close() | |
| await stream.wait_closed() | |
| ::: | |
| ::: method | |
| can_write_eof() | |
| Return `True` if the underlying transport supports the `write_eof`{.interpreted-text role="meth"} method, `False` otherwise. | |
| ::: | |
| ::: method | |
| write_eof() | |
| Close the write end of the stream after the buffered write data is flushed. | |
| ::: | |
| ::: attribute | |
| transport | |
| Return the underlying asyncio transport. | |
| ::: | |
| ::: method | |
| get_extra_info(name, default=None) | |
| Access optional transport information; see `BaseTransport.get_extra_info`{.interpreted-text role="meth"} for details. | |
| ::: | |
| ::: {.method async=""} | |
| drain() | |
| Wait until it is appropriate to resume writing to the stream. Example: | |
| writer.write(data) | |
| await writer.drain() | |
| This is a flow control method that interacts with the underlying IO write buffer. When the size of the buffer reaches the high watermark, *drain()* blocks until the size of the buffer is drained down to the low watermark and writing can be resumed. When there is nothing to wait for, the `drain`{.interpreted-text role="meth"} returns immediately. | |
| ::: | |
| ::::: {.method async=""} | |
| start_tls(sslcontext, \*, server_hostname=None, ssl_handshake_timeout=None, ssl_shutdown_timeout=None) | |
| Upgrade an existing stream-based connection to TLS. | |
| Parameters: | |
| - *sslcontext*: a configured instance of `~ssl.SSLContext`{.interpreted-text role="class"}. | |
| - *server_hostname*: sets or overrides the host name that the target server\'s certificate will be matched against. | |
| - *ssl_handshake_timeout* is the time in seconds to wait for the TLS handshake to complete before aborting the connection. `60.0` seconds if `None` (default). | |
| - *ssl_shutdown_timeout* is the time in seconds to wait for the SSL shutdown to complete before aborting the connection. `30.0` seconds if `None` (default). | |
| ::: versionadded | |
| 3.11 | |
| ::: | |
| ::: versionchanged | |
| 3.12 Added the *ssl_shutdown_timeout* parameter. | |
| ::: | |
| ::::: | |
| :::: method | |
| is_closing() | |
| Return `True` if the stream is closed or in the process of being closed. | |
| ::: versionadded | |
| 3.7 | |
| ::: | |
| :::: | |
| :::: {.method async=""} | |
| wait_closed() | |
| Wait until the stream is closed. | |
| Should be called after `close`{.interpreted-text role="meth"} to wait until the underlying connection is closed, ensuring that all data has been flushed before e.g. exiting the program. | |
| ::: versionadded | |
| 3.7 | |
| ::: | |
| :::: | |
| :::::::::::::::::: | |
| ## Examples | |
| ### TCP echo client using streams {#asyncio-tcp-echo-client-streams} | |
| TCP echo client using the `asyncio.open_connection`{.interpreted-text role="func"} function: | |
| import asyncio | |
| async def tcp_echo_client(message): | |
| reader, writer = await asyncio.open_connection( | |
| '127.0.0.1', 8888) | |
| print(f'Send: {message!r}') | |
| writer.write(message.encode()) | |
| await writer.drain() | |
| data = await reader.read(100) | |
| print(f'Received: {data.decode()!r}') | |
| print('Close the connection') | |
| writer.close() | |
| await writer.wait_closed() | |
| asyncio.run(tcp_echo_client('Hello World!')) | |
| ::: seealso | |
| The `TCP echo client protocol <asyncio_example_tcp_echo_client_protocol>`{.interpreted-text role="ref"} example uses the low-level `loop.create_connection`{.interpreted-text role="meth"} method. | |
| ::: | |
| ### TCP echo server using streams {#asyncio-tcp-echo-server-streams} | |
| TCP echo server using the `asyncio.start_server`{.interpreted-text role="func"} function: | |
| import asyncio | |
| async def handle_echo(reader, writer): | |
| data = await reader.read(100) | |
| message = data.decode() | |
| addr = writer.get_extra_info('peername') | |
| print(f"Received {message!r} from {addr!r}") | |
| print(f"Send: {message!r}") | |
| writer.write(data) | |
| await writer.drain() | |
| print("Close the connection") | |
| writer.close() | |
| await writer.wait_closed() | |
| async def main(): | |
| server = await asyncio.start_server( | |
| handle_echo, '127.0.0.1', 8888) | |
| addrs = ', '.join(str(sock.getsockname()) for sock in server.sockets) | |
| print(f'Serving on {addrs}') | |
| async with server: | |
| await server.serve_forever() | |
| asyncio.run(main()) | |
| ::: seealso | |
| The `TCP echo server protocol <asyncio_example_tcp_echo_server_protocol>`{.interpreted-text role="ref"} example uses the `loop.create_server`{.interpreted-text role="meth"} method. | |
| ::: | |
| ### Get HTTP headers | |
| Simple example querying HTTP headers of the URL passed on the command line: | |
| import asyncio | |
| import urllib.parse | |
| import sys | |
| async def print_http_headers(url): | |
| url = urllib.parse.urlsplit(url) | |
| if url.scheme == 'https': | |
| reader, writer = await asyncio.open_connection( | |
| url.hostname, 443, ssl=True) | |
| else: | |
| reader, writer = await asyncio.open_connection( | |
| url.hostname, 80) | |
| query = ( | |
| f"HEAD {url.path or '/'} HTTP/1.0\r\n" | |
| f"Host: {url.hostname}\r\n" | |
| f"\r\n" | |
| ) | |
| writer.write(query.encode('latin-1')) | |
| while True: | |
| line = await reader.readline() | |
| if not line: | |
| break | |
| line = line.decode('latin1').rstrip() | |
| if line: | |
| print(f'HTTP header> {line}') | |
| # Ignore the body, close the socket | |
| writer.close() | |
| await writer.wait_closed() | |
| url = sys.argv[1] | |
| asyncio.run(print_http_headers(url)) | |
| Usage: | |
| python example.py http://example.com/path/page.html | |
| or with HTTPS: | |
| python example.py https://example.com/path/page.html | |
| ### Register an open socket to wait for data using streams {#asyncio_example_create_connection-streams} | |
| Coroutine waiting until a socket receives data using the `open_connection`{.interpreted-text role="func"} function: | |
| import asyncio | |
| import socket | |
| async def wait_for_data(): | |
| # Get a reference to the current event loop because | |
| # we want to access low-level APIs. | |
| loop = asyncio.get_running_loop() | |
| # Create a pair of connected sockets. | |
| rsock, wsock = socket.socketpair() | |
| # Register the open socket to wait for data. | |
| reader, writer = await asyncio.open_connection(sock=rsock) | |
| # Simulate the reception of data from the network | |
| loop.call_soon(wsock.send, 'abc'.encode()) | |
| # Wait for data | |
| data = await reader.read(100) | |
| # Got data, we are done: close the socket | |
| print("Received:", data.decode()) | |
| writer.close() | |
| await writer.wait_closed() | |
| # Close the second socket | |
| wsock.close() | |
| asyncio.run(wait_for_data()) | |
| ::: seealso | |
| The `register an open socket to wait for data using a protocol | |
| <asyncio_example_create_connection>`{.interpreted-text role="ref"} example uses a low-level protocol and the `loop.create_connection`{.interpreted-text role="meth"} method. | |
| The `watch a file descriptor for read events | |
| <asyncio_example_watch_fd>`{.interpreted-text role="ref"} example uses the low-level `loop.add_reader`{.interpreted-text role="meth"} method to watch a file descriptor. | |
| ::: | |