|
| 1 | +# userver.py Demo of simple uasyncio-based echo server |
| 2 | + |
| 3 | +# Released under the MIT licence |
| 4 | +# Copyright (c) Peter Hinch 2019 |
| 5 | + |
| 6 | +import usocket as socket |
| 7 | +import uasyncio as asyncio |
| 8 | +import uselect as select |
| 9 | +import ujson |
| 10 | + |
| 11 | +class Server: |
| 12 | + @staticmethod |
| 13 | + async def flash(): # ESP8266 only: demo that it is nonblocking |
| 14 | + from machine import Pin |
| 15 | + pin = Pin(2, Pin.OUT) |
| 16 | + while True: |
| 17 | + pin(not pin()) |
| 18 | + await asyncio.sleep_ms(100) |
| 19 | + |
| 20 | + async def run(self, loop, port=8123, led=True): |
| 21 | + addr = socket.getaddrinfo('0.0.0.0', port, 0, socket.SOCK_STREAM)[0][-1] |
| 22 | + s_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # server socket |
| 23 | + s_sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) |
| 24 | + s_sock.bind(addr) |
| 25 | + s_sock.listen(5) |
| 26 | + self.socks = [s_sock] # List of current sockets for .close() |
| 27 | + print('Awaiting connection on port', port) |
| 28 | + poller = select.poll() |
| 29 | + poller.register(s_sock, select.POLLIN) |
| 30 | + client_id = 1 # For user feedback |
| 31 | + if led: |
| 32 | + loop.create_task(self.flash()) |
| 33 | + while True: |
| 34 | + res = poller.poll(1) # 1ms block |
| 35 | + if res: # Only s_sock is polled |
| 36 | + c_sock, _ = s_sock.accept() # get client socket |
| 37 | + loop.create_task(self.run_client(c_sock, client_id)) |
| 38 | + client_id += 1 |
| 39 | + await asyncio.sleep_ms(200) |
| 40 | + |
| 41 | + async def run_client(self, sock, cid): |
| 42 | + self.socks.append(sock) |
| 43 | + sreader = asyncio.StreamReader(sock) |
| 44 | + swriter = asyncio.StreamWriter(sock, {}) |
| 45 | + print('Got connection from client', cid) |
| 46 | + try: |
| 47 | + while True: |
| 48 | + res = await sreader.readline() |
| 49 | + if res == b'': |
| 50 | + raise OSError |
| 51 | + print('Received {} from client {}'.format(ujson.loads(res.rstrip()), cid)) |
| 52 | + await swriter.awrite(res) # Echo back |
| 53 | + except OSError: |
| 54 | + pass |
| 55 | + print('Client {} disconnect.'.format(cid)) |
| 56 | + sock.close() |
| 57 | + self.socks.remove(sock) |
| 58 | + |
| 59 | + def close(self): |
| 60 | + print('Closing {} sockets.'.format(len(self.socks))) |
| 61 | + for sock in self.socks: |
| 62 | + sock.close() |
| 63 | + |
| 64 | +loop = asyncio.get_event_loop() |
| 65 | +server = Server() |
| 66 | +try: |
| 67 | + loop.run_until_complete(server.run(loop)) |
| 68 | +except KeyboardInterrupt: |
| 69 | + print('Interrupted') # This mechanism doesn't work on Unix build. |
| 70 | +finally: |
| 71 | + server.close() |
0 commit comments