circuitpython: Socket closing if timed out and no data on socket
If no data is received on a socket, and the socket has timed out, a socket will close. Subsequent reads raise OSError: [Errno 9] EBADF
.
I dug deeper, this behavior is expected (https://github.com/adafruit/circuitpython/blob/main/ports/esp32s2/common-hal/socketpool/Socket.c#L123) on the esp32-s2.
However, closing the socket immediately makes it difficult to poll a socket to check if data is available.
For example, polling a socket for a response, like in MiniMQTT (https://github.com/brentru/Adafruit_CircuitPython_MiniMQTT/blob/cpython-s2/adafruit_minimqtt/adafruit_minimqtt.py#L872), raises OSError instead of simply timing out and leaving the socket open.
0
bytearray(b'\n')
recv from socket...
Traceback (most recent call last):
File "code.py", line 47, in <module>
OSError: [Errno 9] EBADF
Could we instead raise a timeout or perform some other behavior? CPython raises a socket.timeout
(https://docs.python.org/3.8/library/socket.html#socket.timeout) error for this operation and leaves the socket open.
Code example, , receiving one byte of code at a time from a server, until it reads 0
:
import time
import ssl
import socketpool
import wifi
import board
import neopixel
# Add a secrets.py to your filesystem that has a dictionary called secrets with "ssid" and
# "password" keys with your WiFi credentials. DO NOT share that file or commit it into Git or other
# source control.
# pylint: disable=no-name-in-module,wrong-import-order
try:
from secrets import secrets
except ImportError:
print("WiFi secrets are kept in secrets.py, please add them there!")
raise
print("Connecting to %s"%secrets["ssid"])
wifi.radio.connect(secrets["ssid"], secrets["password"])
print("Connected to %s!"%secrets["ssid"])
# Create a socket pool
pool = socketpool.SocketPool(wifi.radio)
# Host
host = "0.tcp.ngrok.io"
port = 10480
addr_info = pool.getaddrinfo(
host, port, 0, pool.SOCK_STREAM
)[0]
sock = pool.socket(
addr_info[0], addr_info[1], addr_info[2]
)
sock.connect((host, port))
sock.settimeout(1)
buf = bytearray(1)
# attempt to recv
while True:
print("recv from socket...")
time.sleep(2)
data = sock.recv_into(buf, 1)
print(data)
print(buf)
Then I set up a simple tcp packet server using netcat (nc -l 23999
)
Output:
Connected to!
recv from socket...
1
bytearray(b'h')
recv from socket...
1
bytearray(b'e')
recv from socket...
1
bytearray(b'l')
recv from socket...
1
bytearray(b'l')
recv from socket...
1
bytearray(b'o')
recv from socket...
1
bytearray(b'\n')
recv from socket...
0
bytearray(b'\n')
recv from socket...
Traceback (most recent call last):
File "code.py", line 47, in <module>
OSError: [Errno 9] EBADF
About this issue
- Original URL
- State: closed
- Created 4 years ago
- Comments: 15 (8 by maintainers)
@hierophect please chat with @tannewt and @brentru, im not the one using the code 😃