Twisted's Connection
class inherits the write
method from the abstract class FileDescriptor
. As you can see here, the class has a buffer which is not flushed until the total number of buffered bytes is greater than bufferSize
(attribute in class FileDescriptor
).
For my specific needs, I'd like to write data to the socket as soon as possible, so I would like to avoid buffering them at any point of the transmission. I have set TCP_NODELAY
to the socket but data is still buffered at Twisted's write
call.
So, my approach to tackle this is to call FileDescriptor.doWrite
method, which will try to write any data in the buffer (see source). I call doWrite
always after write
as follows:
...
self.transport.write(data)
self.transport.doWrite()
...
The workaround seems to be working fine but, from time to time, the following bug comes to the surface:
self.transport.doWrite() # Flush twisted buffer
File "/usr/local/lib/python2.7/dist-packages/Twisted-14.0.2-py2.7-linux-x86_64.egg/twisted/internet/abstract.py", line 270, in doWrite
self.stopWriting()
File "/usr/local/lib/python2.7/dist-packages/Twisted-14.0.2-py2.7-linux-x86_64.egg/twisted/internet/abstract.py", line 429, in stopWriting
self.reactor.removeWriter(self)
File "/usr/local/lib/python2.7/dist-packages/Twisted-14.0.2-py2.7-linux-x86_64.egg/twisted/internet/epollreactor.py", line 344, in removeWriter
EPOLLOUT, EPOLLIN)
File "/usr/local/lib/python2.7/dist-packages/Twisted-14.0.2-py2.7-linux-x86_64.egg/twisted/internet/epollreactor.py", line 322, in _remove
primary.remove(fd)
KeyError: 11
The problem is that doWrite
calls stopWriting
, which attempts to remove itself (the Connection
object) from the writers list in the reactor
. The exception raises because it cannot find this object in the list.
It's strange because write
should register the reader in case the data
argument is not None
(I thought the problem was that data sometimes was None
, so I included write
& doWrite
under the condition of data being present). So, I decided to just catch the KeyError
exception and ignore it as follows:
...
if data:
self.transport.write(data)
try:
self.transport.doWrite()
except KeyError:
pass
...
Yet, the exception keeps popping and even closes the TCP connection.
I don't know where and why the exception is raised now that I catch it in doWrite
. Also, I don't know what are the side-effects of this hack. It might be that I'm oversimplifying the whole Twisted's file descriptor paradigm (I don't understand it enough yet). I also don't know if this is the actual expected behaviour, shouldn't Twisted check whether the element is in the list of writers before removing it from the list in any case?