Streams — Python documentation
Streams
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.
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())
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 section below.
Stream Functions
The following top-level asyncio functions can be used to create and work with streams:
Unix Sockets
StreamReader
- class asyncio.StreamReader
Represents a reader object that provides APIs to read data from the IO stream.
It is not recommended to instantiate StreamReader objects directly; use
open_connection()
andstart_server()
instead.- at_eof()
Return
True
if the buffer is empty andfeed_eof()
was called.
StreamWriter
- class asyncio.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()
andstart_server()
instead.- can_write_eof()
Return
True
if the underlying transport supports the write_eof() method,False
otherwise.
- write_eof()
Close the write end of the stream after the buffered write data is flushed.
- transport
Return the underlying asyncio transport.
- get_extra_info(name, default=None)
Access optional transport information; see BaseTransport.get_extra_info() for details.
- write(data)
Write data to the stream.
This method is not subject to flow control. Calls to
write()
should be followed bydrain()
.
- writelines(data)
Write a list (or any iterable) of bytes to the stream.
This method is not subject to flow control. Calls to
writelines()
should be followed bydrain()
.
- close()
Close the stream.
- is_closing()
Return
True
if the stream is closed or in the process of being closed.New in version 3.7.
Examples
TCP echo client using streams
TCP echo client using the asyncio.open_connection()
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())
data = await reader.read(100)
print(f'Received: {data.decode()!r}')
print('Close the connection')
writer.close()
asyncio.run(tcp_echo_client('Hello World!'))
TCP echo server using streams
TCP echo server using the asyncio.start_server()
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()
async def main():
server = await asyncio.start_server(
handle_echo, '127.0.0.1', 8888)
addr = server.sockets[0].getsockname()
print(f'Serving on {addr}')
async with server:
await server.serve_forever()
asyncio.run(main())
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()
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
Coroutine waiting until a socket receives data using the open_connection()
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()
# Close the second socket
wsock.close()
asyncio.run(wait_for_data())
See also
The register an open socket to wait for data using a protocol example uses a low-level protocol and the loop.create_connection()
method.
The watch a file descriptor for read events example uses the low-level loop.add_reader() method to watch a file descriptor.