5. 网络 - TCP 套接字¶
大多数互联网的构建块是 TCP 套接字。这些套接字在连接的网络设备之间提供可靠的字节流。本教程的这一部分将展示如何在几种不同的情况下使用 TCP 套接字。
5.1. 星球大战 Asciimation¶
最简单的方法是从互联网上下载数据。在这种情况下,我们将使用blinkenlights.nl 网站提供的Star Wars Asciimation 服务。它使用端口 23 上的 telnet 协议将数据流式传输到任何连接的人。它使用起来非常简单,因为它不需要您进行身份验证(提供用户名或密码),您可以立即开始下载数据。
首先要做的是确保我们有可用的套接字模块:
>>> import socket
然后获取服务器的IP地址:
>>> addr_info = socket.getaddrinfo("towel.blinkenlights.nl", 23)
该 getaddrinfo
函数实际上返回一个地址列表,每个地址包含的信息比我们需要的要多。我们只想获取第一个有效地址,然后只获取服务器的 IP 地址和端口。要做到这一点,请使用:
>>> addr = addr_info[0][-1]
如果您键入addr_info
并 addr
在提示符下,您将确切地看到它们保存的信息。
使用 IP 地址,我们可以创建一个套接字并连接到服务器:
>>> s = socket.socket()
>>> s.connect(addr)
现在我们已连接,我们可以下载并显示数据:
>>> while True:
... data = s.recv(500)
... print(str(data, 'utf8'), end='')
...
当这个循环执行时,它应该开始显示动画(使用 ctrl-C 来中断它)。
如果您想尝试一下,您还应该能够使用普通 Python 在您的 PC 上运行相同的代码。
5.2. HTTP GET 请求¶
下一个示例显示如何下载网页。HTTP 使用端口 80,您首先需要发送“GET”请求,然后才能下载任何内容。作为请求的一部分,您需要指定要检索的页面。
让我们定义一个可以下载和打印 URL 的函数:
def http_get(url):
import socket
_, _, host, path = url.split('/', 3)
addr = socket.getaddrinfo(host, 80)[0][-1]
s = socket.socket()
s.connect(addr)
s.send(bytes('GET /%s HTTP/1.0\r\nHost: %s\r\n\r\n' % (path, host), 'utf8'))
while True:
data = s.recv(100)
if data:
print(str(data, 'utf8'), end='')
else:
break
s.close()
那你可以试试:
>>> http_get('http://micropython.org/ks/test.html')
这应该检索网页并将 HTML 打印到控制台。
5.3. 简单的 HTTP 服务器¶
以下代码创建了一个简单的 HTTP 服务器,该服务器为单个网页提供服务,该网页包含一个包含所有 GPIO 引脚状态的表格:
import machine
pins = [machine.Pin(i, machine.Pin.IN) for i in (0, 2, 4, 5, 12, 13, 14, 15)]
html = """<!DOCTYPE html>
<html>
<head> <title>ESP8266 Pins</title> </head>
<body> <h1>ESP8266 Pins</h1>
<table border="1"> <tr><th>Pin</th><th>Value</th></tr> %s </table>
</body>
</html>
"""
import socket
addr = socket.getaddrinfo('0.0.0.0', 80)[0][-1]
s = socket.socket()
s.bind(addr)
s.listen(1)
print('listening on', addr)
while True:
cl, addr = s.accept()
print('client connected from', addr)
cl_file = cl.makefile('rwb', 0)
while True:
line = cl_file.readline()
if not line or line == b'\r\n':
break
rows = ['<tr><td>%s</td><td>%d</td></tr>' % (str(p), p.value()) for p in pins]
response = html % '\n'.join(rows)
cl.send('HTTP/1.0 200 OK\r\nContent-type: text/html\r\n\r\n')
cl.send(response)
cl.close()