Reputation: 2183
I'm trying to set up a simple server/client connection using the socket module on a Raspberry Pi Pico W running the latest nightly build image rp2-pico-w-20221123-unstable-v1.19.1-713-g7fe7c55bb.uf2 which I've downloaded from https://micropython.org/download/rp2-pico-w/
The following code runs fine for the first connection (network connectivity can be assumed at this point).
import socket
def await_connection():
print(' >> Awaiting connection ...')
try:
host_addr = socket.getaddrinfo('0.0.0.0', 46321)[0][-1]
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
sock.bind(host_addr)
sock.listen(1)
con, addr = sock.accept()
while True:
# keep receiving commands on the open connection until the client stops sending
cmd = con.recv(1024)
if not cmd:
print(f' >> {addr} disconnected')
break
elif cmd.decode() == 'foo':
response = 'bar'.encode()
else:
response = cmd
print(f"Received {cmd.decode()}")
print(f"Returning {response.decode()}")
con.sendall(response)
except OSError as e:
print(f' >> ERROR: {e}')
finally:
# appearantly, context managers are currently not supported in MicroPython, therefore the connection is closed manually
con.close()
print(' >> Connection closed.')
while True:
# main loop, causing the program to await a new connection as soon as the previous one is closed
await_connection()
If the client closes the connection and tries to re-connect, the infamous [Errno 98] EADDRINUSE is thrown:
Please note that I've already implemented the sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
statement, as recommended here, but to no avail.
However, if I run the exact same code on a Raspberry Pi 3 B with python 3.7.3 within the same network, everything works as expected - the client can disconnect and reconnect multiple times without issues:
How do I get the Pico to reuse the address after the initial connection, just like it is working in python 3.7.3?
Upvotes: 3
Views: 7891
Reputation: 2183
While I was able to mitigate the reconnection crash by adding a sock.close()
statement after the con.close()
, the main issue with my code was the structure itself, as Steffen Ullrich pointed out.
The actual fix was to move the operations on the sock object out of the loop.
import socket
def await_connection():
print(' >> Awaiting connection ...')
try:
con, addr = sock.accept()
while True:
# keep receiving commands on the open connection until the client stops sending
cmd = con.recv(1024)
if not cmd:
print(f' >> {addr} disconnected')
break
else:
response = cmd
print(f"Received {cmd.decode()}")
print(f"Returning {response.decode()}")
con.sendall(response)
except OSError as e:
print(f' >> ERROR: {e}')
finally:
# appearantly, context managers are currently not supported in MicroPython, therefore the connection is closed manually
con.close()
print(' >> Connection closed.')
host_addr = socket.getaddrinfo('0.0.0.0', 46321)[0][-1]
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
sock.bind(host_addr)
sock.listen(1)
while True:
# main loop, causing the program to await a new connection as soon as the previous one is closed
await_connection()
Upvotes: 4