[Twisted-Python] ENOBUF and Twisted
James Y Knight
foom at fuhm.net
Sat Aug 21 13:56:11 MDT 2004
On Aug 21, 2004, at 3:50 AM, Jp Calderone wrote:
> How many clients are we talking about? A bit of investigation leads
> me to believe this can be caused by reaching the maximum number of
> open sockets. Having unreliable connections can exacerbate this,
> since TIME_WAIT sockets are counted towards the limit (Windows NT 4.0
> seems to leave sockets in this state for 4 minutes).
> Twisted should still probably handle it, but if this is the true
> cause, it should be handled in a fashion similar to errors from
> accept(), possibly (a better understanding of the problem is probably
> still required).
I don't think that's the case, or rather, it is the case for accept()
but not write().
From my understanding, ENOBUF on send() could come about because there
is a limit on the amount of kernel buffer space a process is allowed to
consume and a previous send() call consumed it all, after select() said
there was space remaining. Thus, there was no space for this write to
proceed, and the kernel returned that error. I believe it should be
treated as a transient error, and the send retried later. So, it should
go in the same case as EWOULDBLOCK.
However, from the original description, it sounds like perhaps there
may be some byte limit over which you cannot even attempt to write.
This makes some amount of sense -- the kernel doesn't want to have to
copy a gigantic buffer into kernel space just to discard most of it.
So, how about: self.socket.send(buffer(data, 0, 65535)). I'm not sure
if that's necessary or not.
Apparently accept() can also return ENOBUFS, for the same kinds of
reasons, and should also be treated as a transient error. I suspect
EMFILE and ENFILE should also be handled the same way. But that's a
Screwtape (I guess that's probably not your real name, but you don't
seem to have given a real name),
Can you try this patch and see if it fixes the problem? It assumes
you'll always be able to send a 64K buffer *eventually*, which I hope
is the case. If you could also try it with just the "or se.args ==
ENOBUFS", and not the buffer(.., 0, 65535), that'd also be appreciated.
--- twisted/internet/tcp.py (revision 11325)
+++ twisted/internet/tcp.py (working copy)
@@ -58,6 +58,7 @@
EISCONN = 10056
ENOTCONN = 10057
EINTR = 10004
+ from errno import WSAENOBUFS as ENOBUFS
elif os.name != 'java':
from errno import EPERM
from errno import EINVAL
@@ -68,6 +69,7 @@
from errno import EISCONN
from errno import ENOTCONN
from errno import EINTR
+ from errno import ENOBUFS
from errno import EAGAIN
# Twisted Imports
@@ -262,11 +264,11 @@
(which is negative)
- return self.socket.send(data)
+ return self.socket.send(buffer(data, 0, 65535))
except socket.error, se:
if se.args == EINTR:
- elif se.args == EWOULDBLOCK:
+ elif se.args == EWOULDBLOCK or se.args == ENOBUFS:
More information about the Twisted-Python