1

我正在尝试组装一个简单的温度计,它可以在 OLED 显示屏上提供温度,也可以通过使用 MicroPython 的 ESP8266 上的 http 请求提供温度。

轮询对象已用于防止websocket阻塞循环(因此可以更新测量值和 OLED 显示)。

#CREATE SOCKET
serverSocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
serverSocket.bind(('', 80))
serverSocket.listen(5)

#REGISTER SOCKET TO THE POLLER
pollerObject = select.poll()
pollerObject.register(serverSocket, select.POLLIN)

#PERFORM FIRST MEASUREMENT AT STARTUP
last_meas_time = startup_time
sensor_readings = read_sensor()
print(sensor_readings)
display.display_measurement(str(temp),str(hum))

#LOOP FOREVER
while True:
    
    #ONE MEASUREMENT UPDATE EVERY 30s
    if(time.time() - last_meas_time >= 30):
        sensor_readings = read_sensor()
        print(sensor_readings)
        display.display_measurement(str(temp),str(hum))
        last_meas_time = time.time()
    
    #WAIT UP TO 10s FOR INCOMING CONNECTIONS
    fdVsEvent = pollerObject.poll(10000)
    
    for descriptor, Event in fdVsEvent:
        print()
        print("Got an incoming connection request")
        print("Start processing")
        # Do accept() on server socket or read from a client socket
        conn, addr = serverSocket.accept()
        print('Got a connection from %s' % str(addr))
        request = conn.recv(1024)
        print('Content = %s' % str(request))
        response = web_page()
        conn.send('HTTP/1.1 200 OK\n')
        conn.send('Content-Type: text/html\n')
        conn.send('Connection: close\n\n')
        conn.sendall(response)
        conn.close()

它似乎在一段时间内运行良好,但我发现了两个问题,希望能得到您的帮助:

  1. 即使我只连接一次,在 shell 终端中也会显示2 或 3 个请求,如下所示。为什么会发生这种情况,我该如何解决?是否可以让浏览器等待足够长的时间来发送第二个或第三个请求?
    MPY:软重启
    连接成功
    ('192.168.1.74', '255.255.255.0', '192.168.1.1', '192.168.1.1')
    b'29.0,24.0'
    
    收到传入的连接请求
    开始处理
    从 ('192.168.1.64', 58581) 获得连接
    内容 = b'GET / HTTP/1.1\r\nHost: 192.168.1.74\r\nConnection: keep-alive\r\nCache-Control: max-age=0\r\nDNT: 1\r\nUpgrade-Insecure-请求:1\r\n用户代理:Mozilla/5.0(Windows NT 10.0;Win64;x64)AppleWebKit/537.36(KHTML,如 Gecko)Chrome/87.0.4280.88 Safari/537.36 Edg/87.0.664.66\r\n接受:文本/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9\r\n接受-编码:gzip,放气\r\n接受语言:pt-BR,pt;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6,sv;q=0.5 \r\n\r\n'
    
    收到传入的连接请求
    开始处理
    从 ('192.168.1.64', 58582) 获得连接
    Content = b'GET /favicon.ico HTTP/1.1\r\nHost: 192.168.1.74\r\nConnection: keep-alive\r\nPragma: no-cache\r\nCache-Control: no-cache\r\nUser -代理:Mozilla/5.0(Windows NT 10.0;Win64;x64)AppleWebKit/537.36(KHTML,如 Gecko)Chrome/87.0.4280.88 Safari/537.36 Edg/87.0.664.66\r\nDNT:1\r\n接受:图像/ webp,image/apng,image/*,*/*;q=0.8\r\nReferer: http://192.168.1.74/\r\nAccept-Encoding: gzip, deflate\r\nAccept-Language: pt-BR ,pt;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6,sv;q=0.5\r\n\r\n'
  1. 运行一段时间后,我将无法再连接到它,因为它不会响应。我的方法明显有问题吗?这是我从控制台得到的:
    收到传入的连接请求
    开始处理
    从 ('192.168.1.64', 59158) 获得连接
    内容 = b'GET / HTTP/1.1\r\nHost: 192.168.1.74\r\nConnection: keep-alive\r\nCache-Control: max-age=0\r\nDNT: 1\r\nUpgrade-Insecure-请求:1\r\n用户代理:Mozilla/5.0(Windows NT 10.0;Win64;x64)AppleWebKit/537.36(KHTML,如 Gecko)Chrome/87.0.4280.88 Safari/537.36 Edg/87.0.664.66\r\n接受:文本/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9\r\n接受-编码:gzip,放气\r\n接受语言:pt-BR,pt;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6,sv;q=0.5 \r\n\r\n'
    
    收到传入的连接请求
    开始处理
    从 ('192.168.1.64', 59157) 获得连接
    Content = b'GET /favicon.ico HTTP/1.1\r\nHost: 192.168.1.74\r\nConnection: keep-alive\r\nPragma: no-cache\r\nCache-Control: no-cache\r\nUser -代理:Mozilla/5.0(Windows NT 10.0;Win64;x64)AppleWebKit/537.36(KHTML,如 Gecko)Chrome/87.0.4280.88 Safari/537.36 Edg/87.0.664.66\r\nDNT:1\r\n接受:图像/ webp,image/apng,image/*,*/*;q=0.8\r\nReferer: http://192.168.1.74/\r\nAccept-Encoding: gzip, deflate\r\nAccept-Language: pt-BR ,pt;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6,sv;q=0.5\r\n\r\n'
    
    收到传入的连接请求
    开始处理
    从 ('192.168.1.64', 59160) 获得连接
    内容 = b''
    回溯(最近一次通话最后):
      文件“main.py”,第 104 行,在
    操作系统错误:[Errno 104] ECONNRESET
    MicroPython v1.13 于 2020-09-11;ESP8266 ESP模块
    键入“help()”以获取更多信息。
    >>>

第 104 行对应于:

        conn.sendall(response)

谢谢!

4

1 回答 1

2

即使我只连接一次,在 shell 终端中也会显示 2 或 3 个请求,如下所示。为什么会发生这种情况,我该如何解决?是否可以让浏览器等待足够长的时间来发送第二个或第三个请求?

这取决于浏览器如何连接到您的服务器。浏览器可能正在寻找多个请求,或者浏览器具有连接到服务器的套接字的超时值。我没有任何网络知识,但它看起来像是对不同信息的两个请求。该信息是如何处理的,应该传递给web_page(). 看起来您正在发送整个网页,而不是它正在寻找的特定内容。

运行一段时间后,我将无法再连接到它,因为它不会响应。我的方法有明显的问题吗?

可能发生的情况是您socket.sendall()阻止了任何新套接字的创建。另请注意,即使您已正确关闭套接字,套接字仍可能有数据要发送。它已被标记为关闭,但操作系统可能尚未关闭它。

使用select.poll(). 乍一看,注册您serverSocketpollerObject(select.poll) 似乎可以处理未来的连接。这不是正在发生的事情。您仅将一个套接字注册到pollerObject. severSocket正在从浏览器获取传入连接的事件select.POLLIN。您需要一种方法来添加/注册由serverSocketto创建的新套接字,pollerObject以便您可以服务其他套接字。

现在,您在 micropython 中尝试做的最好的例子是制作类似于Python 3 Selectors中的选择器示例的东西。

import selectors
import socket

sel = selectors.DefaultSelector()

def accept(sock, mask):
    conn, addr = sock.accept()  # Should be ready
    print('accepted', conn, 'from', addr)
    conn.setblocking(False)
    sel.register(conn, selectors.EVENT_READ, read)

def read(conn, mask):
    data = conn.recv(1000)  # Should be ready
    if data:
        print('echoing', repr(data), 'to', conn)
        conn.send(data)  # Hope it won't block
    else:
        print('closing', conn)
        sel.unregister(conn)
        conn.close()

sock = socket.socket()
sock.bind(('localhost', 1234))
sock.listen(100)
sock.setblocking(False)
sel.register(sock, selectors.EVENT_READ, accept)

while True:
    events = sel.select()
    for key, mask in events:
        callback = key.data
        callback(key.fileobj, mask)

通常,您不必担心用 填充套接字传输缓冲区socket.send(),但您应该处理它。现在,我会在之前和之后放置一些调试打印,socket.sendall()因为这将阻塞/重试,直到发送所有数据。在没有发送所有数据的情况下,您必须为写入就绪事件注册套接字,并传递需要发送的剩余数据。这有点复杂。

Got an incoming connection request
Start processing
Got a connection from ('192.168.1.64', 59160)
Content = b''
Traceback (most recent call last):
  File "main.py", line 104, in 
OSError: [Errno 104] ECONNRESET
MicroPython v1.13 on 2020-09-11; ESP module with ESP8266
Type "help()" for more information.
>>> 

您在上面遇到的问题是您可能有一个已超时的套接字连接。TCP 让您知道连接已过期。您应该使用 try except else 子句来处理这个问题。

于 2021-04-08T19:50:48.017 回答