使用 usocket 似乎停止了循环(micropython)
using usocket seems to halt the loop (micropython)
我正在尝试为 ESP32 开发板编写一个简单的程序。
我的主程序相当简单,它必须 运行 循环。
另一方面,设备还需要能够以非常简单的响应来响应 HTTP 请求。
这是我的尝试(https://randomnerdtutorials.com/micropython-esp32-esp8266-bme280-web-server/ 的返工):
try:
import usocket as socket
except:
import socket
from micropython import const
import time
REFRESH_DELAY = const(60000) #millisecondi
def do_connect():
import network
wlan = network.WLAN(network.STA_IF)
wlan.active(True)
if not wlan.isconnected():
print('connecting to network...')
wlan.config(dhcp_hostname=HOST)
wlan.connect('SSID', 'PSWD')
while not wlan.isconnected():
pass
print('network config:', wlan.ifconfig())
import json
import esp
esp.osdebug(None)
import gc
gc.collect()
do_connect()
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind((HOST, SENSOR_SCKT_PORT))
s.listen(5)
prevRun = 0
i = 0
while True:
print("iteration #"+str(i))
i += 1
# run every 60 seconds
curRun = int(round(time.time() * 1000))
if curRun - prevRun >= REFRESH_DELAY:
prevRun = curRun
# MAIN PROGRAM
# ......
# whole bunch of code
# ....
# run continuously:
try:
if gc.mem_free() < 102000:
gc.collect()
conn, addr = s.accept()
conn.settimeout(3.0)
print('Got a connection from %s' % str(addr))
request = conn.recv(1024)
conn.settimeout(None)
request = str(request)
#print('Content = %s' % request)
measurements = 'some json stuff'
conn.send('HTTP/1.1 200 OK\n')
conn.send('Content-Type: text/html\n')
conn.send('Connection: close\n\n')
conn.send(measurements)
conn.close()
except OSError as e:
conn.close()
print('Connection closed')
我只得到第 0 次迭代,然后 while True
循环停止。
如果我用 HTTP 请求 ping 这个服务器,我得到一个正确的响应,并且循环前进到迭代#1 和#2(不知道为什么它认为我用 2 个请求 ping 它)。
所以似乎 socket.listen(5) 正在停止 while 循环。
有什么办法可以避免这种情况吗?
还有其他解决方案吗?
我不认为线程在这里是一个选项。
问题是 s.accept()
是一个阻塞调用...它不会 return 直到它收到一个连接。这就是它暂停循环的原因。
最简单的解决方案可能是在调用 s.accept()
之前检查连接是否正在等待;您可以使用 select.select
或 select.poll
来完成此操作。我更喜欢 select.poll
API,它最终看起来像这样:
import esp
import gc
import json
import machine
import network
import select
import socket
import time
from micropython import const
HOST = '0.0.0.0'
SENSOR_SCKT_PORT = const(1234)
REFRESH_DELAY = const(60000) # milliseconds
def wait_for_connection():
print('waiting for connection...')
wlan = network.WLAN(network.STA_IF)
while not wlan.isconnected():
machine.idle()
print('...connected. network config:', wlan.ifconfig())
esp.osdebug(None)
gc.collect()
wait_for_connection()
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind((HOST, SENSOR_SCKT_PORT))
s.listen(5)
poll = select.poll()
poll.register(s, select.POLLIN)
prevRun = 0
i = 0
while True:
print("iteration #"+str(i))
i += 1
# run every 60 seconds
curRun = int(round(time.time() * 1000))
if curRun - prevRun >= REFRESH_DELAY:
prevRun = curRun
# MAIN PROGRAM
# ......
# whole bunch of code
# ....
# run continuously:
try:
if gc.mem_free() < 102000:
gc.collect()
events = poll.poll(100)
if events:
conn, addr = s.accept()
conn.settimeout(3.0)
print('Got a connection from %s' % str(addr))
request = conn.recv(1024)
conn.settimeout(None)
request = str(request)
# print('Content = %s' % request)
measurements = 'some json stuff'
conn.send('HTTP/1.1 200 OK\n')
conn.send('Content-Type: text/html\n')
conn.send('Connection: close\n\n')
conn.send(measurements)
conn.close()
except OSError:
conn.close()
print('Connection closed')
您会注意到,为了在我的设备上 运行 并安抚我的风格,我对您的代码进行了一些改动;首先,我删除了大部分 do_connect
方法并将所有 import
放在文件顶部。
唯一真正的变化是:
我们创建一个select.poll()
对象:
poll = select.poll()
我们要求它监视 s
变量的 POLLIN
事件:
poll.register(s, select.POLLIN)
我们在尝试处理连接之前检查是否有任何连接挂起:
events = poll.poll(100)
if events:
conn, addr = s.accept()
conn.settimeout(3.0)
[...]
进行这些更改后,运行 您的代码和发出请求看起来像这样:
iteration #0
iteration #1
iteration #2
iteration #3
iteration #4
iteration #5
iteration #6
Got a connection from ('192.168.1.169', 54392)
iteration #7
iteration #8
iteration #9
iteration #10
请注意,如此处所写,您的循环将至少每 100 毫秒迭代一次(您可以通过更改我们对 poll.poll()
的调用的超时来控制它)。
注意:以上是在 esp8266 设备(Wemos D1 克隆)运行 MicroPython v1.13-268-gf7aafc062
).
上测试的
我正在尝试为 ESP32 开发板编写一个简单的程序。 我的主程序相当简单,它必须 运行 循环。 另一方面,设备还需要能够以非常简单的响应来响应 HTTP 请求。
这是我的尝试(https://randomnerdtutorials.com/micropython-esp32-esp8266-bme280-web-server/ 的返工):
try:
import usocket as socket
except:
import socket
from micropython import const
import time
REFRESH_DELAY = const(60000) #millisecondi
def do_connect():
import network
wlan = network.WLAN(network.STA_IF)
wlan.active(True)
if not wlan.isconnected():
print('connecting to network...')
wlan.config(dhcp_hostname=HOST)
wlan.connect('SSID', 'PSWD')
while not wlan.isconnected():
pass
print('network config:', wlan.ifconfig())
import json
import esp
esp.osdebug(None)
import gc
gc.collect()
do_connect()
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind((HOST, SENSOR_SCKT_PORT))
s.listen(5)
prevRun = 0
i = 0
while True:
print("iteration #"+str(i))
i += 1
# run every 60 seconds
curRun = int(round(time.time() * 1000))
if curRun - prevRun >= REFRESH_DELAY:
prevRun = curRun
# MAIN PROGRAM
# ......
# whole bunch of code
# ....
# run continuously:
try:
if gc.mem_free() < 102000:
gc.collect()
conn, addr = s.accept()
conn.settimeout(3.0)
print('Got a connection from %s' % str(addr))
request = conn.recv(1024)
conn.settimeout(None)
request = str(request)
#print('Content = %s' % request)
measurements = 'some json stuff'
conn.send('HTTP/1.1 200 OK\n')
conn.send('Content-Type: text/html\n')
conn.send('Connection: close\n\n')
conn.send(measurements)
conn.close()
except OSError as e:
conn.close()
print('Connection closed')
我只得到第 0 次迭代,然后 while True
循环停止。
如果我用 HTTP 请求 ping 这个服务器,我得到一个正确的响应,并且循环前进到迭代#1 和#2(不知道为什么它认为我用 2 个请求 ping 它)。
所以似乎 socket.listen(5) 正在停止 while 循环。
有什么办法可以避免这种情况吗? 还有其他解决方案吗? 我不认为线程在这里是一个选项。
问题是 s.accept()
是一个阻塞调用...它不会 return 直到它收到一个连接。这就是它暂停循环的原因。
最简单的解决方案可能是在调用 s.accept()
之前检查连接是否正在等待;您可以使用 select.select
或 select.poll
来完成此操作。我更喜欢 select.poll
API,它最终看起来像这样:
import esp
import gc
import json
import machine
import network
import select
import socket
import time
from micropython import const
HOST = '0.0.0.0'
SENSOR_SCKT_PORT = const(1234)
REFRESH_DELAY = const(60000) # milliseconds
def wait_for_connection():
print('waiting for connection...')
wlan = network.WLAN(network.STA_IF)
while not wlan.isconnected():
machine.idle()
print('...connected. network config:', wlan.ifconfig())
esp.osdebug(None)
gc.collect()
wait_for_connection()
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind((HOST, SENSOR_SCKT_PORT))
s.listen(5)
poll = select.poll()
poll.register(s, select.POLLIN)
prevRun = 0
i = 0
while True:
print("iteration #"+str(i))
i += 1
# run every 60 seconds
curRun = int(round(time.time() * 1000))
if curRun - prevRun >= REFRESH_DELAY:
prevRun = curRun
# MAIN PROGRAM
# ......
# whole bunch of code
# ....
# run continuously:
try:
if gc.mem_free() < 102000:
gc.collect()
events = poll.poll(100)
if events:
conn, addr = s.accept()
conn.settimeout(3.0)
print('Got a connection from %s' % str(addr))
request = conn.recv(1024)
conn.settimeout(None)
request = str(request)
# print('Content = %s' % request)
measurements = 'some json stuff'
conn.send('HTTP/1.1 200 OK\n')
conn.send('Content-Type: text/html\n')
conn.send('Connection: close\n\n')
conn.send(measurements)
conn.close()
except OSError:
conn.close()
print('Connection closed')
您会注意到,为了在我的设备上 运行 并安抚我的风格,我对您的代码进行了一些改动;首先,我删除了大部分 do_connect
方法并将所有 import
放在文件顶部。
唯一真正的变化是:
我们创建一个
select.poll()
对象:poll = select.poll()
我们要求它监视
s
变量的POLLIN
事件:poll.register(s, select.POLLIN)
我们在尝试处理连接之前检查是否有任何连接挂起:
events = poll.poll(100) if events: conn, addr = s.accept() conn.settimeout(3.0) [...]
进行这些更改后,运行 您的代码和发出请求看起来像这样:
iteration #0
iteration #1
iteration #2
iteration #3
iteration #4
iteration #5
iteration #6
Got a connection from ('192.168.1.169', 54392)
iteration #7
iteration #8
iteration #9
iteration #10
请注意,如此处所写,您的循环将至少每 100 毫秒迭代一次(您可以通过更改我们对 poll.poll()
的调用的超时来控制它)。
注意:以上是在 esp8266 设备(Wemos D1 克隆)运行 MicroPython v1.13-268-gf7aafc062
).