diff --git a/uasyncio_iostream/poll/client_r.py b/uasyncio_iostream/poll/client_r.py new file mode 100644 index 0000000..da7266b --- /dev/null +++ b/uasyncio_iostream/poll/client_r.py @@ -0,0 +1,55 @@ +# client_r.py Test poll object's response to two fault conditions under Unix and ESP8266 +import usocket as socket +import uasyncio as asyncio +import uselect as select + +server_addr = socket.getaddrinfo('192.168.0.35', 8123)[0][-1] +s = socket.socket() +s.connect(server_addr) # Expect OSError if server down +poller = select.poll() +poller.register(s, select.POLLIN) +s.setblocking(False) + +success = False +async def run(): + global success + ok = True + try: + while ok: + res = poller.ipoll(10) + for sock, ev in res: + if ev & select.POLLIN: + r = sock.readline() + print(ev, r) + # A server outage prints 1, b'' forever on ESP8266 or Unix. + # If killer closes socket on ESP8266 ev is always 1, + # on Unix get ev == 32 + # Never see 9 or 17 (base 10) which are the error responses expected by uasyncio + # (POLLIN & POLLERR or POLLIN & POLLHUP) + else: # The only way I can make it work (on Unix) is to quit on 32 + print('Terminating event:', ev) # What is 32?? + ok = False + break + await asyncio.sleep(0) + except OSError: + print('Got OSError') # Never happens + success = True # Detected socket closure or error by OSError or event + +async def killer(): + await asyncio.sleep(5) + print('closing socket') + s.close() + for n in range(3, -1, -1): + print('Shutdown in {}s'.format(n)) # Leave time for response from run() + await asyncio.sleep(1) + if success: + print('Success: detected error/socket closure.') + else: + print('Failed to detect error/socket closure.') + +loop = asyncio.get_event_loop() +loop.create_task(run()) +try: + loop.run_until_complete(killer()) +finally: + s.close() diff --git a/uasyncio_iostream/poll/client_w.py b/uasyncio_iostream/poll/client_w.py new file mode 100644 index 0000000..cb5c943 --- /dev/null +++ b/uasyncio_iostream/poll/client_w.py @@ -0,0 +1,55 @@ +# client_w.py Test poll object's response to two fault conditions under Unix and ESP8266 +import usocket as socket +import uasyncio as asyncio +import uselect as select + +server_addr = socket.getaddrinfo('192.168.0.35', 8123)[0][-1] +s = socket.socket() +s.connect(server_addr) # Expect OSError if server down +poller = select.poll() +poller.register(s, select.POLLOUT) +s.setblocking(False) + +success = False +async def run(): + global success + ok = True + try: + while ok: + res = poller.ipoll(10) + for sock, ev in res: + if ev & select.POLLOUT: + r = sock.send(b'0123456789\n') + print(ev, r) + # On ESP8266 if another task closes the socket the poll object + # never triggers. uasyncio expects it to trigger with POLLHUP or + # (POLLOUT & POLLERR or POLLOUT & POLLHUP) + # If server fails gets OSError rather than above response. + else: # But on Unix server failure or socket closure produces ev == 32 + print('Terminating event:', ev) # What is 32?? + ok = False + break + await asyncio.sleep(1) + await asyncio.sleep(0) + except OSError: + print('Got OSError') # Happens on ESP8266 if server fails + success = True # Detected socket closure or error by OSError or event + +async def killer(): + await asyncio.sleep(5) + print('closing socket') + s.close() + for n in range(3, -1, -1): + print('Shutdown in {}s'.format(n)) # Leave time for response from run() + await asyncio.sleep(1) + if success: + print('Success: detected error/socket closure.') + else: + print('Failed to detect error/socket closure.') + +loop = asyncio.get_event_loop() +loop.create_task(run()) +try: + loop.run_until_complete(killer()) +finally: + s.close() diff --git a/uasyncio_iostream/poll/server.py b/uasyncio_iostream/poll/server.py new file mode 100644 index 0000000..cb7530f --- /dev/null +++ b/uasyncio_iostream/poll/server.py @@ -0,0 +1,44 @@ +# Minimal stream based socket seerver. To test client exception handling. Can +# only handle a single client but will cope with client failure and reconnect. +# Run under MicroPython Unix build. + +import usocket as socket +import utime +addr = socket.getaddrinfo('0.0.0.0', 8123)[0][-1] + +s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) +s.bind(addr) +s.listen(1) + +def run(write=True): + try: + while True: + print('Awaiting connection.') + try: + conn, addr = s.accept() + except OSError as er: + print('Connect fail:', er.args[0]) + conn.close() + continue + + print('Got connection from', addr) + try: + while True: + if write: + conn.send(b'0123456789\n') # OSError on fail + utime.sleep(1) + else: + line = conn.readline() + if line == b'': + print('Connection fail') + break + else: + print(line) + except OSError: + conn.close() + finally: + conn.close() + s.close() + +print('run() to send lines of 11 bytes on port 8123,') +print('run(False) to read lines')