8000 examples/network: Split recv- and read-based HTTP servers. · ladyada/circuitpython@3d19adf · GitHub
[go: up one dir, main page]

Skip to content

Commit 3d19adf

Browse files
committed
examples/network: Split recv- and read-based HTTP servers.
Name recv() based a "simplistic", as it can't work robustly in every environment. All this is to let people concentreate on proper, read()- based one (and to turn recv() based into a "negative showcase", explaining what are the pitfalls of such approach).
1 parent d79342d commit 3d19adf

File tree

3 files changed

+143
-18
lines changed

3 files changed

+143
-18
lines changed

examples/network/http_server.py

Lines changed: 29 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
Hello #%d from MicroPython!
1111
"""
1212

13-
def main(use_stream=False):
13+
def main(micropython_optimize=False):
1414
s = socket.socket()
1515

1616
# Binding to all interfaces - server will be accessible to other hosts!
@@ -26,26 +26,37 @@ def main(use_stream=False):
2626
counter = 0
2727
while True:
2828
res = s.accept()
29-
client_s = res[0]
29+
client_sock = res[0]
3030
client_addr = res[1]
3131
print("Client address:", client_addr)
32-
print("Client socket:", client_s)
33-
print("Request:")
34-
if use_stream:
35-
# MicroPython socket objects support stream (aka file) interface
36-
# directly.
37-
req = client_s.readline()
38-
print(req)
39-
while True:
40-
h = client_s.readline()
41-
if h == b"" or h == b"\r\n":
42-
break
43-
print(h)
44-
client_s.write(CONTENT % counter)
32+
print("Client socket:", client_sock)
33+
34+
if not micropython_optimize:
35+
# To read line-oriented protocol (like HTTP) from a socket (and
36+
# avoid short read problem), it must be wrapped in a stream (aka
37+
# file-like) object. That's how you do it in CPython:
38+
client_stream = client_sock.makefile("rwb")
4539
else:
46-
print(client_s.recv(4096))
47-
client_s.send(CONTENT % counter)
48-
client_s.close()
40+
# .. but MicroPython socket objects support stream interface
41+
# directly, so calling .makefile() method is not required. If
42+
# you develop application which will run only on MicroPython,
43+
# especially on a resource-constrained embedded device, you
44+
# may take this shortcut to save resources.
45+
client_stream = client_sock
46+
47+
print("Request:")
48+
req = client_stream.readline()
49+
print(req)
50+
while True:
51+
h = client_stream.readline()
52+
if h == b"" or h == b"\r\n":
53+
break
54+
print(h)
55+
client_stream.write(CONTENT % counter)
56+
57+
client_stream.close()
58+
if not micropython_optimize:
59+
client_sock.close()
4960
counter += 1
5061
print()
5162

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
try:
2+
import usocket as socket
3+
except:
4+
import socket
5+
6+
7+
CONTENT = b"""\
8+
HTTP/1.0 200 OK
9+
10+
Hello #%d from MicroPython!
11+
"""
12+
13+
def main():
14+
s = socket.socket()
15+
ai = socket.getaddrinfo("0.0.0.0", 8080)
16+
addr = ai[0][-1]
17+
18+
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
19+
20+
s.bind(addr)
21+
s.listen(5)
22+
print("Listening, connect your browser to http://<this_host>:8080/")
23+
24+
counter = 0
25+
while True:
26+
res = s.accept()
27+
client_s = res[0]
28+
client_addr = res[1]
29+
req = client_s.recv(4096)
30+
print("Request:")
31+
print(req)
32+
client_s.send(CONTENT % counter)
33+
client_s.close()
34+
counter += 1
35+
print()
36+
37+
38+
main()
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
#
2+
# MicroPython http_server_simplistic.py example
3+
#
4+
# This example shows how to write the smallest possible HTTP
5+
# server in MicroPython. With comments and convenience code
6+
# removed, this example can be compressed literally to ten
7+
# lines. There's a catch though - read comments below for
8+
# details, and use this code only for quick hacks, preferring
9+
# http_server.py for "real thing".
10+
#
11+
try:
12+
import usocket as socket
13+
except:
14+
import socket
15+
16+
17+
CONTENT = b"""\
18+
HTTP/1.0 200 OK
19+
20+
Hello #%d from MicroPython!
21+
"""
22+
23+
def main():
24+
s = socket.socket()
25+
26+
# Bind to (allow to be connected on ) all interfaces. This means
27+
# this server will be accessible to other hosts on your local
28+
# network, and if your server has direct (non-firewalled) connection
29+
# to the Internet, then to anyone on the Internet. We bind to all
30+
# interfaces to let this example work easily on embedded MicroPython
31+
# targets, which you will likely access from another machine on your
32+
# local network. Take care when running this on an Internet-connected
33+
# machine though! Replace "0.0.0.0" with "127.0.0.1" if in doubt, to
34+
# make the server accessible only on the machine it runs on.
35+
ai = socket.getaddrinfo("0.0.0.0", 8080)
36+
print("Bind address info:", ai)
37+
addr = ai[0][-1]
38+
39+
# A port on which a socket listened remains inactive during some time.
40+
# This means that if you run this sample, terminate it, and run again
41+
# you will likely get an error. To avoid this timeout, set SO_REUSEADDR
42+
# socket option.
43+
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
44+
45+
s.bind(addr)
46+
s.listen(5)
47+
print("Listening, connect your browser to http://<this_host>:8080/")
48+
49+
counter = 0
50+
while True:
51+
res = s.accept()
52+
client_s = res[0]
53+
client_addr = res[1]
54+
print("Client address:", client_addr)
55+
print("Client socket:", client_s)
56+
# We assume here that .recv() call will read entire HTTP request
57+
# from client. This is usually true, at least on "big OS" systems
58+
# like Linux/MacOS/Windows. But that doesn't have to be true in
59+
# all cases, in particular on embedded systems, when there can
60+
# easily be "short recv", where it returns much less than requested
61+
# data size. That's why this example is called "simplistic" - it
62+
# shows that writing a web server in Python that *usually works* is
63+
# ten lines of code, and you can use this technique for quick hacks
64+
# and experimentation. But don't do it like that in production
65+
# applications - instead, parse HTTP request properly, as shown
66+
# by http_server.py example.
67+
req = client_s.recv(4096)
68+
print("Request:")
69+
print(req)
70+
client_s.send(CONTENT % counter)
71+
client_s.close()
72+
counter += 1
73+
print()
74+
75+
76+
main()

0 commit comments

Comments
 (0)
0