diff --git a/examples/network/http_server.py b/examples/network/http_server.py index 147bf5122..e3a66e828 100644 --- a/examples/network/http_server.py +++ b/examples/network/http_server.py @@ -10,7 +10,7 @@ HTTP/1.0 200 OK Hello #%d from MicroPython! """ -def main(use_stream=False): +def main(micropython_optimize=False): s = socket.socket() # Binding to all interfaces - server will be accessible to other hosts! @@ -26,26 +26,37 @@ def main(use_stream=False): counter = 0 while True: res = s.accept() - client_s = res[0] + client_sock = res[0] client_addr = res[1] print("Client address:", client_addr) - print("Client socket:", client_s) - print("Request:") - if use_stream: - # MicroPython socket objects support stream (aka file) interface - # directly. - req = client_s.readline() - print(req) - while True: - h = client_s.readline() - if h == b"" or h == b"\r\n": - break - print(h) - client_s.write(CONTENT % counter) + print("Client socket:", client_sock) + + if not micropython_optimize: + # To read line-oriented protocol (like HTTP) from a socket (and + # avoid short read problem), it must be wrapped in a stream (aka + # file-like) object. That's how you do it in CPython: + client_stream = client_sock.makefile("rwb") else: - print(client_s.recv(4096)) - client_s.send(CONTENT % counter) - client_s.close() + # .. but MicroPython socket objects support stream interface + # directly, so calling .makefile() method is not required. If + # you develop application which will run only on MicroPython, + # especially on a resource-constrained embedded device, you + # may take this shortcut to save resources. + client_stream = client_sock + + print("Request:") + req = client_stream.readline() + print(req) + while True: + h = client_stream.readline() + if h == b"" or h == b"\r\n": + break + print(h) + client_stream.write(CONTENT % counter) + + client_stream.close() + if not micropython_optimize: + client_sock.close() counter += 1 print() diff --git a/examples/network/http_server_simplistic.py b/examples/network/http_server_simplistic.py new file mode 100644 index 000000000..f932e48f5 --- /dev/null +++ b/examples/network/http_server_simplistic.py @@ -0,0 +1,38 @@ +try: + import usocket as socket +except: + import socket + + +CONTENT = b"""\ +HTTP/1.0 200 OK + +Hello #%d from MicroPython! +""" + +def main(): + s = socket.socket() + ai = socket.getaddrinfo("0.0.0.0", 8080) + addr = ai[0][-1] + + s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + + s.bind(addr) + s.listen(5) + print("Listening, connect your browser to http://:8080/") + + counter = 0 + while True: + res = s.accept() + client_s = res[0] + client_addr = res[1] + req = client_s.recv(4096) + print("Request:") + print(req) + client_s.send(CONTENT % counter) + client_s.close() + counter += 1 + print() + + +main() diff --git a/examples/network/http_server_simplistic_commented.py b/examples/network/http_server_simplistic_commented.py new file mode 100644 index 000000000..b58e9eeb6 --- /dev/null +++ b/examples/network/http_server_simplistic_commented.py @@ -0,0 +1,76 @@ +# +# MicroPython http_server_simplistic.py example +# +# This example shows how to write the smallest possible HTTP +# server in MicroPython. With comments and convenience code +# removed, this example can be compressed literally to ten +# lines. There's a catch though - read comments below for +# details, and use this code only for quick hacks, preferring +# http_server.py for "real thing". +# +try: + import usocket as socket +except: + import socket + + +CONTENT = b"""\ +HTTP/1.0 200 OK + +Hello #%d from MicroPython! +""" + +def main(): + s = socket.socket() + + # Bind to (allow to be connected on ) all interfaces. This means + # this server will be accessible to other hosts on your local + # network, and if your server has direct (non-firewalled) connection + # to the Internet, then to anyone on the Internet. We bind to all + # interfaces to let this example work easily on embedded MicroPython + # targets, which you will likely access from another machine on your + # local network. Take care when running this on an Internet-connected + # machine though! Replace "0.0.0.0" with "127.0.0.1" if in doubt, to + # make the server accessible only on the machine it runs on. + ai = socket.getaddrinfo("0.0.0.0", 8080) + print("Bind address info:", ai) + addr = ai[0][-1] + + # A port on which a socket listened remains inactive during some time. + # This means that if you run this sample, terminate it, and run again + # you will likely get an error. To avoid this timeout, set SO_REUSEADDR + # socket option. + s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + + s.bind(addr) + s.listen(5) + print("Listening, connect your browser to http://:8080/") + + counter = 0 + while True: + res = s.accept() + client_s = res[0] + client_addr = res[1] + print("Client address:", client_addr) + print("Client socket:", client_s) + # We assume here that .recv() call will read entire HTTP request + # from client. This is usually true, at least on "big OS" systems + # like Linux/MacOS/Windows. But that doesn't have to be true in + # all cases, in particular on embedded systems, when there can + # easily be "short recv", where it returns much less than requested + # data size. That's why this example is called "simplistic" - it + # shows that writing a web server in Python that *usually works* is + # ten lines of code, and you can use this technique for quick hacks + # and experimentation. But don't do it like that in production + # applications - instead, parse HTTP request properly, as shown + # by http_server.py example. + req = client_s.recv(4096) + print("Request:") + print(req) + client_s.send(CONTENT % counter) + client_s.close() + counter += 1 + print() + + +main()