micropython: Bugs and limitations of socket module

On the A9G board, with s being a Berkeley socket (import socket; s = socket.socket()) entering the following commands yields errors:

  • s.recv(50) when rx buffer is empty freezes the board, even after a s.settimeout(3),
  • s.connect((url, port)) executed twice in a row freezes the board,
  • looking at s yields <socket> only.

By comparison, behaviors of those commands on an ESP8266 with the latest firmware are:

  • s.recv(50) when rx buffer is empty results in an OSError: [Errno 110] ETIMEDOUT error, after having set s.settimeout(3),
  • s.connect((url, port)) executed twice yields an OSError: 106 error, and the socket remains connected,
  • looking at s yields <socket state=0 timeout=-1 incoming=0 off=0> which gives enhanced state of the socket (e.g., to track network errors).

About this issue

  • Original URL
  • State: open
  • Created 4 years ago
  • Reactions: 1
  • Comments: 18 (5 by maintainers)

Commits related to this issue

Most upvoted comments

So I kept testing and it turns out that the problem is not the voltage or the socket.close() method.

There’s a problem with socket.recv(). After removing this from the code I was able to loop indefinetely without the module rebooting because it hangs, and the data gets correctly transmitted every time.

I do need to access the response from the server as it contains a few variables that the program inside the module uses.

I’ve read that other modules like ESP32 and ESP8266 have had this problem but they have been corrected so I don’t know why this happens with the latest version of micropython.

UPDATE:

I solved it by replacing response=s.recv(256) with

ready = select.select([s], [], [], 5)
if ready[0]:
     response=s.recv(256)

Now it loops forever without hanging 😃

The latest build produces this:

>>> s.setblocking(False)
>>> s.connect(('demo.traccar.org', 5055))
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
OSError: [Errno 115] EINPROGRESS
>>> s.connect(('demo.traccar.org', 5055))
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
OSError: 106

I do not know whether it is a fair result but, at least, it does not halt the module and is easy to implement.

I fixed one limiting case instead of the core problem which requires patching. Some of the underlying lwip exceptions are not written in errno: they are, for some reason, redirected to the platform error handler which displays an error in coolwatcher and halts the module. I will try to fix it.

I fixed this:

  1. When s.connect called twice OSError(EISCONN) is raised
  2. When calling s.recv on empty socket OSError(ENOTCONN) is raised (on ESP8266 it’s OSError(0))

Socket errors can be traced in cooltools. I was not able to reproduce the timeout problem: please provide a minimal working example.