diff --git a/docs/library/uasyncio.rst b/docs/library/uasyncio.rst index 0c71702420..0abbf8dd8d 100644 --- a/docs/library/uasyncio.rst +++ b/docs/library/uasyncio.rst @@ -237,9 +237,11 @@ TCP stream connections This is a coroutine. -.. method:: Stream.read(n) +.. method:: Stream.read(n=-1) - Read up to *n* bytes and return them. + Read up to *n* bytes and return them. If *n* is not provided or -1 then read all + bytes until EOF. The returned value will be an empty bytes object if EOF is + encountered before any bytes are read. This is a coroutine. diff --git a/extmod/uasyncio/stream.py b/extmod/uasyncio/stream.py index 750d8e9740..785e43555d 100644 --- a/extmod/uasyncio/stream.py +++ b/extmod/uasyncio/stream.py @@ -26,9 +26,17 @@ class Stream: # TODO yield? self.s.close() - async def read(self, n): - yield core._io_queue.queue_read(self.s) - return self.s.read(n) + async def read(self, n=-1): + r = b"" + while True: + yield core._io_queue.queue_read(self.s) + r2 = self.s.read(n) + if r2 is not None: + if n >= 0: + return r2 + if not len(r2): + return r + r += r2 async def readinto(self, buf): yield core._io_queue.queue_read(self.s) diff --git a/tests/multi_net/uasyncio_tcp_readall.py b/tests/multi_net/uasyncio_tcp_readall.py new file mode 100644 index 0000000000..c411f1c69d --- /dev/null +++ b/tests/multi_net/uasyncio_tcp_readall.py @@ -0,0 +1,60 @@ +# Test uasyncio stream read(-1) method using TCP server/client + +try: + import uasyncio as asyncio +except ImportError: + try: + import asyncio + except ImportError: + print("SKIP") + raise SystemExit + +PORT = 8000 + + +async def handle_connection(reader, writer): + writer.write(b"a") + await writer.drain() + + # Split the first 2 bytes up so the client must wait for the second one + await asyncio.sleep(0.1) + + writer.write(b"b") + await writer.drain() + + writer.write(b"c") + await writer.drain() + + print("close") + writer.close() + await writer.wait_closed() + + print("done") + ev.set() + + +async def tcp_server(): + global ev + ev = asyncio.Event() + server = await asyncio.start_server(handle_connection, "0.0.0.0", PORT) + print("server running") + multitest.next() + async with server: + await asyncio.wait_for(ev.wait(), 2) + + +async def tcp_client(): + reader, writer = await asyncio.open_connection(IP, PORT) + print(await reader.read()) + print(await reader.read()) # should be empty + print(await reader.read(1)) # should be empty + + +def instance0(): + multitest.globals(IP=multitest.get_network_ip()) + asyncio.run(tcp_server()) + + +def instance1(): + multitest.next() + asyncio.run(tcp_client()) diff --git a/tests/multi_net/uasyncio_tcp_readall.py.exp b/tests/multi_net/uasyncio_tcp_readall.py.exp new file mode 100644 index 0000000000..0bf3dcba60 --- /dev/null +++ b/tests/multi_net/uasyncio_tcp_readall.py.exp @@ -0,0 +1,8 @@ +--- instance0 --- +server running +close +done +--- instance1 --- +b'abc' +b'' +b''