This issue tracker has been migrated to GitHub ,
and is currently read-only.
For more information,
see the GitHub FAQs in the Python's Developer Guide.
Created on 2015年01月30日 01:28 by piotrjurkiewicz, last changed 2022年04月11日 14:58 by admin. This issue is now closed.
| Files | ||||
|---|---|---|---|---|
| File name | Uploaded | Description | Edit | |
| test_unix_sock_timeout.py | neologix, 2015年01月30日 08:03 | |||
| Messages (6) | |||
|---|---|---|---|
| msg235013 - (view) | Author: Piotr Jurkiewicz (piotrjurkiewicz) * | Date: 2015年01月30日 01:28 | |
After setting socket.settimeout(5.0), socket.send() returns immediately, instead of returning after specified timeout.
Steps to reproduce:
Open two python interpreters.
In the first one (the receiver) execute:
>>> import socket
>>> r = socket.socket(socket.AF_UNIX, socket.SOCK_DGRAM)
>>> r.bind("test.sock")
In the second one (the sender) execute:
>>> import socket
>>> s = socket.socket(socket.AF_UNIX, socket.SOCK_DGRAM)
Then run the following command 11 times:
>>> s.sendto("msg", "test.sock")
On the 12 run command will block. This happens because datagram sockets queue on Linux is 11 messages long. Interrupt the command.
So far so good.
Then set sender socket timeout:
>>> s.settimeout(5.0)
Expected behavior:
s.sendto() should block for a 5 seconds and THEN raise error 11 (EAGAIN/EWOULDBLOCK).
Actual behavior:
s.sendto() raises the error IMMEDIATELY.
>>> s.sendto("msg", "test.sock")
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
socket.error: [Errno 11] Resource temporarily unavailable
So, in fact, s.settimeout(5.0) does not have any effect.
I think that problem is that settimeout() sets the socket to the non-blocking mode (docs say: "Timeout mode internally sets the socket in non-blocking mode.").
As described [here](http://stackoverflow.com/q/13556972/2178047) setting timeout on non-blocking sockets is impossible.
In fact, when I set timeout manually with setsockopt(), everything works as expected:
>>> s.setblocking(1) #go back to blocking mode
>>> tv = struct.pack("ll", 5, 0)
>>> s.setsockopt(socket.SOL_SOCKET, socket.SO_SNDTIMEO, tv)
Now s.sendto() raises the error after 5 seconds, as expected.
|
|||
| msg235015 - (view) | Author: Antoine Pitrou (pitrou) * (Python committer) | Date: 2015年01月30日 01:34 | |
The way socket timeouts are implemented is by using select() to determine whether the socket is ready for read/write. In this case, select() probably marks the socket ready even though the queue is full, which later raises EAGAIN. About SO_SNDTIMEO and SO_RCVTIMEO, POSIX says "it is implementation-defined whether the SO_SNDTIMEO option can be set". Also, they would not necessarily apply to other operations such as accept(). |
|||
| msg235028 - (view) | Author: Charles-François Natali (neologix) * (Python committer) | Date: 2015年01月30日 08:03 | |
> The way socket timeouts are implemented is by using select() to determine whether the socket is ready for read/write. In this case, select() probably marks the socket ready even though the queue is full, which later raises EAGAIN.
Indeed, and this looks like a kernel bug.
Working as expected on a RHEL6:
$ python /tmp/test_unix_sock_timeout.py
('sending ', 0)
took 0.000s
('sending ', 1)
took 0.000s
('sending ', 2)
took 0.000s
('sending ', 3)
took 0.000s
('sending ', 4)
took 0.000s
('sending ', 5)
took 0.000s
('sending ', 6)
took 0.000s
('sending ', 7)
took 0.000s
('sending ', 8)
took 0.000s
('sending ', 9)
took 0.000s
('sending ', 10)
took 0.000s
('sending ', 11)
took 1.000s
Traceback (most recent call last):
File "/tmp/test_unix_sock_timeout.py", line 17, in <module>
s.sendto("hello", SOCKNAME)
socket.timeout: timed out
> About SO_SNDTIMEO and SO_RCVTIMEO, POSIX says "it is implementation-defined whether the SO_SNDTIMEO option can be set". Also, they would not necessarily apply to other operations such as accept().
Exactly, the current way timeouts are implemented ar The Right Way, IMO.
|
|||
| msg235044 - (view) | Author: Antoine Pitrou (pitrou) * (Python committer) | Date: 2015年01月30日 17:31 | |
The test script works on Ubuntu 14.10 as well. |
|||
| msg235416 - (view) | Author: Piotr Jurkiewicz (piotrjurkiewicz) * | Date: 2015年02月05日 01:52 | |
Does not work on Debian 7 Wheezy, kernel 3.2.65.
$ python test.py
('sending ', 0)
took 0.000s
('sending ', 1)
took 0.000s
('sending ', 2)
took 0.000s
('sending ', 3)
took 0.000s
('sending ', 4)
took 0.000s
('sending ', 5)
took 0.000s
('sending ', 6)
took 0.000s
('sending ', 7)
took 0.000s
('sending ', 8)
took 0.000s
('sending ', 9)
took 0.000s
('sending ', 10)
took 0.000s
('sending ', 11)
took 0.000s
Traceback (most recent call last):
File "test.py", line 17, in <module>
s.sendto("hello", SOCKNAME)
socket.error: [Errno 11] Resource temporarily unavailable
$ uname -a
Linux 3.2.0-4-amd64 #1 SMP Debian 3.2.65-1+deb7u1 x86_64 GNU/Linux
|
|||
| msg235422 - (view) | Author: Charles-François Natali (neologix) * (Python committer) | Date: 2015年02月05日 07:37 | |
It's a kernel bug closing (working fine on my Debian wheezy with a more recent kernel BTW). |
|||
| History | |||
|---|---|---|---|
| Date | User | Action | Args |
| 2022年04月11日 14:58:12 | admin | set | github: 67540 |
| 2015年02月05日 07:37:20 | neologix | set | status: open -> closed resolution: third party messages: + msg235422 |
| 2015年02月05日 01:52:11 | piotrjurkiewicz | set | status: pending -> open messages: + msg235416 |
| 2015年02月02日 21:31:34 | neologix | set | status: open -> pending |
| 2015年01月30日 17:31:40 | pitrou | set | messages: + msg235044 |
| 2015年01月30日 08:03:13 | neologix | set | files:
+ test_unix_sock_timeout.py messages: + msg235028 |
| 2015年01月30日 01:34:42 | pitrou | set | nosy:
+ neologix, pitrou messages: + msg235015 versions: - Python 3.2, Python 3.3, Python 3.6 |
| 2015年01月30日 01:28:12 | piotrjurkiewicz | create | |