micropython / micropython

MicroPython - a lean and efficient Python implementation for microcontrollers and constrained systems
https://micropython.org
Other
19.09k stars 7.63k forks source link

WiPy/CC3200: usocket.socket.settimeout() not working? #2402

Closed dmartauz closed 2 weeks ago

dmartauz commented 8 years ago

According to the doc: Set a timeout on blocking socket operations. The value argument can be a nonnegative floating point number expressing seconds, or None. If a non-zero value is given, subsequent socket operations will raise a timeout exception if the timeout period value has elapsed before the operation has completed. If zero is given, the socket is put in non-blocking mode. If None is given, the socket is put in blocking mode. http://micropython.org/resources/docs/en/latest/wipy/library/usocket.html#usocket.socket.settimeout

It obviously throws an error: >>> s.settimeout(5.0) Traceback (most recent call last): File "<stdin>", line 1 SyntaxError: decimal numbers not supported I was not successful with int parameter. Parameter was accepted, but there is no timeout happening for usocket.socket.accept().

deshipu commented 8 years ago

WiPy doesn't have floating point numbers at all. This is not a problem with the socket.

dmartauz commented 8 years ago

I am aware that WiPy does not support float. Thats why I was surprised finding float parameter in WiPy's doc. How am I supposed to use usocket.socket.settimeout() on WiPy platform?

dpgeorge commented 8 years ago

How am I supposed to use usocket.socket.settimeout() on WiPy platform?

You should be able to pass an integer, eg socket.settimeout(5).

peterhinch commented 8 years ago

@dpgeorge In his OP @dmartauz said that using an int failed.

dpgeorge commented 8 years ago

@dpgeorge In his OP @dmartauz said that using an int failed.

Indeed! (I missed that bit.) But looking at the cc3200 code it allows either None or an integer. If it's not working with an int then there's a problem with the underlying implementation of settimeout.

There are then two issues: 1) confusing docs that seem to imply that a float is required; 2) possible non working timeout with accept function.

dmartauz commented 8 years ago

I am adding a simple test I performed after soft reset of host with following FW version: MicroPython v1.8.3-41-g253e1a6 on 2016-08-23

`>>> import socket

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.settimeout(5) s.bind(('', 80)) s.listen(5) conn, addr = s.accept()

` In this point s.accept() hangs indefinitely if there is no connection from other host.

Please let me know if I am doing something wrong.

dpgeorge commented 8 years ago

The code looks correct. @danicampora please advise.

dmartauz commented 7 years ago

Could you please take a look at this issue? Currently all network applications on CC3200 depends on how the network peer handles connection. Applications may hang because of blocking socket. I could not find any work-around for this issue.

I repeated above-mentioned test with quite new build (v1.8.6 on 2016-11-14) with the same blocking result.

Note: I am using latest service-pack for TI CC3200 (CC3100_CC3200_ServicePack_1.0.1.6-2.7.0.0) - maybe it provides slightly different API for socket operations?

dmartauz commented 7 years ago

@dpgeorge Could you please take a look at this issue? I checked with build from 12.6.2017 and it is still present.

dpgeorge commented 7 years ago

@dmartauz I can confirm that it is a problem. The issue is that the CC3100 wifi chip can't set a timeout for the accept operation (only for receive).

In 1686346d53051d77daa662f7cc85614cc4ada06a I worked around this by implementing socket timeout in terms of a non-blocking behaviour combined with a loop to check for timeout. Please test this version to see if it now works for you.

dmartauz commented 7 years ago

@dpgeorge Thanks a lot for implementing solution so fast. I will have possibility to test it on Thursday. For receive operation the timeout should be working as well?

dpgeorge commented 7 years ago

For receive operation the timeout should be working as well?

Yes, timeout should be working for all cases (but maybe there are still some bugs...).

dmartauz commented 7 years ago

@dpgeorge I can confirm that timeout works for accept operation for me. I will test it more during next week together with read/receive and will let you know if there are any more issues. `MicroPython v1.9.1-36-gd94bc67-dirty on 2017-06-22; WiPy with CC3200 Type "help()" for more information.

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.settimeout(5) s.bind(('', 80)) s.listen(5) conn, addr = s.accept() Traceback (most recent call last): File "", line 1, in OSError: [Errno 110] ETIMEDOUT`

dmartauz commented 7 years ago

@dpgeorge Is it possible to set timeout for usocket.socket.connect() as well? Because it seems it's fixed to approx. 10 seconds until SL_ECONNREFUSED (111) is raised in case Internet connection of WiFi access point is down.

dmartauz commented 7 years ago

This post seems to be related: http://forum.43oh.com/topic/6372-cc3200-how-to-reduce-tcp-connect-timeout-when-theres-no-internet/

dpgeorge commented 7 years ago

Is it possible to set timeout for usocket.socket.connect() as well?

A timeout is implemented for socket.connect(), just like the other functions (accept, send, recv). It's done in a similar way to what you link to above (by putting it in non-blocking mode).

It may be that the cc3200 sockets aren't able to function as expected when there is no wifi connection. But anyway, if you can provide a minimal code example that exhibits the issue with connect() then I can look at it.

dmartauz commented 7 years ago

@dpgeorge Simple test functions:

def test1():
    start = time.time()
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM, socket.IPPROTO_TCP)
    s.settimeout(3)
    s.connect(('176.58.119.26', 80))
    finish = time.time()
    print(finish - start)
    s.close()

def test2():
    start = time.time()
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM, socket.IPPROTO_SEC)
    ss = ssl.wrap_socket(s)
    ss.settimeout(3)
    ss.connect(('176.58.119.26', 80))
    finish = time.time()
    print(finish - start)
    s.close()

Both throw OSError: 114 on s.connect()/ss.connect(). Is this behavior ok?

mfallavol commented 7 years ago

If I run the above test1() on my WiPy (latest update) with the ip address of a computer that is turned off, it takes 18 seconds to timeout and does not throw any OS Error. This is causing me quite a headache as I don't want my process to block for that long.

dpgeorge commented 7 years ago

@dmartauz thanks for the tests, they were not doing the correct thing but that's now fixed by 4d55d8805aca614ddafdc4a76abc87af60b1371f

@mfallavol please try your testing again with the latest version, it should timeout. If not then it could be a limitation of the CC3100 firmware.

projectgus commented 2 weeks ago

Closing as this was most likely fixed in the linked commit from 2017