Page 1 of 1
socket.settimeout() not working
Posted: Wed Feb 05, 2020 11:27 am
by Romik
PyBoard 1.1 + Ethernet
Code: Select all
>>> dir(socket.socket)
['__class__', '__name__', 'close', 'send', '__bases__', '__del__', 'accept', 'bind', 'connect', 'listen', 'recv', 'recvfrom', 'sendto', 'setblocking',
'setsockopt', 'settimeout']
>>> dir(socket.socket.settimeout)
['__class__']
>>> host = '10.128.0.148'
>>> NTP_QUERY = bytearray(48)
>>> NTP_QUERY[0] = 0x1b
>>> addr = socket.getaddrinfo(host,123)[0][-1]
>>> s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
>>> s.settimeout(5)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
OSError: [Errno 107] ENOTCONN
Why is this happening and how can this be fixed.
Re: socket.settimeout() not working
Posted: Thu Feb 06, 2020 1:43 am
by jimmo
The socket has to be connected before you can set the timeout. Looking at the code, the reason for this is that the timeout is handled by the NIC layer, and until you're connected (or bound), the socket doesn't know which NIC it's using. (This is when you're relying on the NIC to run the TCP stack for you, i.e. using an external wiznet or something). It's a bit different when you're using LWIP (e.g. PYBD with WiFi).
I don't have wiznet to test this with (I assume that's what you're using?) but I think possibly if you bind the socket first to the local address first then it might work?
Re: socket.settimeout() not working
Posted: Thu Feb 06, 2020 7:36 am
by Romik
All is working fine if host is available..
if the host is not available,
msg = s.recvfrom (48) hangs and does not exit.
Code: Select all
nic = WIZNET5K(SPI(1),Pin.board.X12,Pin.board.X11)
ip = ('10.128.0.206','255.255.255.0','10.128.0.1','8.8.8.8')
nic.ifconfig(ip)
host = 'pool.ntp.org'
addr = socket.getaddrinfo(host,123)[0][-1]
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
# s.settimeout(5)
res = s.sendto(NTP_QUERY, addr)
msg = s.recvfrom(48)
s.close()
Re: socket.settimeout() not working
Posted: Thu Feb 06, 2020 9:38 am
by jimmo
Try setting the timeout after the sendto.
The recvfrom will block unless there's a timeout set. To set a timeout you need the socket to be bound to a NIC. To do so you either need to connect(), bind(), or sendto().
Re: socket.settimeout() not working
Posted: Thu Feb 06, 2020 10:48 am
by Romik
The error has changed:
OSError: [Errno 22] EINVAL
Code: Select all
>>> res = s.sendto(NTP_QUERY, addr)
>>> s.settimeout(5)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
OSError: [Errno 22] EINVAL
Re: socket.settimeout() not working
Posted: Thu Feb 06, 2020 10:52 am
by jimmo
Ahh, I just read more of the code. The WizNet driver doesn't implement settimeout:
from ports/stm32/modnwwiznet5k.c
Code: Select all
STATIC int wiznet5k_socket_settimeout(mod_network_socket_obj_t *socket, mp_uint_t timeout_ms, int *_errno) {
// TODO
*_errno = MP_EINVAL;
return -1;
/*
if (timeout_ms == 0) {
// set non-blocking mode
uint8_t arg = SOCK_IO_NONBLOCK;
WIZCHIP_EXPORT(ctlsocket)(socket->u_param.fileno, CS_SET_IOMODE, &arg);
}
*/
}
It wasn't getting to here before because modsocket requires that it has a NIC (hence the original ENOTCONN error), but yeah, the NIC driver doesn't implement this.
Re: socket.settimeout() not working
Posted: Thu Feb 06, 2020 10:57 am
by Romik
Thank you.

Re: socket.settimeout() not working
Posted: Thu Feb 06, 2020 11:40 am
by Romik
I found in documentation. Sorry. All is working.
Code: Select all
# Instead of:
s.settimeout(1.0) # time in seconds
s.read(10) # may timeout
# Use:
poller = uselect.poll()
poller.register(s, uselect.POLLIN)
res = poller.poll(1000) # time in milliseconds
if not res:
# s is still not ready for input, i.e. operation timed out
My code:
Code: Select all
addr = socket.getaddrinfo(host,123)[0][-1]
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
res = s.sendto(NTP_QUERY, addr)
poller = uselect.poll()
poller.register(s, uselect.POLLIN)
res = poller.poll(1000)
if not res:
return 0
else:
msg = s.recvfrom(48)
s.close()