Reputation: 1743
I have the following code of twisted server listening to clients
class Echo(LineReceiver):
def connectionMade(self):
self.factory.clients.append(self)
self.setRawMode()
self._peer = self.transport.getPeer()
timerClass(self)
def connectionLost(self, reason):
self.factory.clients.remove(self)
print 'Lost connection from', self._peer
def why(self):
print str(self._peer) + "we"
self.transport.abortConnection()
def timerClass(self):
t = Timer(2.0, lambda:why(self))
t.start()
According to my code the client should disconnect after 2 seconds after it connects to server. But the client doesn't disconnect after 2 seconds, it disconnect after 2nd client connects to server. Why is it happening like this, I am not bale to figure out.
Upvotes: 0
Views: 129
Reputation: 1832
The thing that jumps out at me is your Timer
call, where is that from? It is timeit.Timer
?
The reason it jumps out at me is that Twisted's behavior goes all screwy if you block the reactor, and unless I'm mistaken that call is a blocking sleep. (I also find some refs to a threading timer
call, which is also likely cause trouble in twisted because much of twisted isn't thread safe, so the following answer still applies)
Generally in Twisted you want to use reactor.callLater
delay method for this style of application. See: http://twistedmatrix.com/documents/current/core/howto/time.html
I'm guessing that your code isn't really waiting for the next connection, but that the sleep is blocking the next connection until the timer runs out, at which time you see your second connection connect and your first connection die.
Give reactor.callLater
a try in place of your Timer call and see if that fixes your issue. If not update your question with more code/test-examples
Update (... comment points out this problem was threading
not timeit
)
Given many parts of Twisted aren't thread-safe (where "not safe" means anything could happen - the behavior isn't predicable), the following is only a guess, but I think its a plausible explanation of the odd behavior you were seeing:
reactor.run
sets up a select
/epoll
/which-ever-event-call-style-of-loop with just your comms file-descriptor registered to wake the event call and it goes to sleep.timerClass
is run, but twisted goes back to sleep, blissfully unaware of the thread. That means:self.transport.abortConnection
some vars get set that intend to shutdown the connection but the work behind those vars can't be executed until Twisted wakes back up (... my specifics might be particularly wrong here, I haven't dug through the abortConnection
codebase to make sure this is the reality of that call)abortConnection
process, which started in the threaded call can be completed, killing the first connection.The test for this theory would be to have the first connection send data, after the thread Timer
ran transport.abortConnection
. Receive data should wake Twisted, and following with my theory, should let the transport.abortConnection
finish without requiring a second connection.
With all that said, the fix is the same. Switch to Twisted's reactor.callLater
, which registers a timer directly into Twisted's event-sleep.
If your interested in a longer breakdown of Twisted vs threads see my answer on How to run a program and also execute code...
Upvotes: 1