我有以下代码的扭曲服务器监听客户端
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()
根据我的代码,客户端应在连接到服务器2秒后断开连接。但是客户端在2秒后没有断开连接,它在第二个客户端连接到服务器后断开连接。为什么会这样发生,我不敢弄明白。
答案 0 :(得分:1)
向我跳出来的是你的Timer
电话,来自哪里?它是timeit.Timer
?
它向我跳出来的原因是,如果你阻挡反应堆,Twisted的行为会变得一团糟,除非我错了,这个叫声是一个阻塞的睡眠。 (我也发现一些线程timer
调用的参考,这也可能导致扭曲的麻烦,因为大部分扭曲不是线程安全的,所以以下答案仍然适用)
通常在Twisted中,您希望对此应用程序样式使用reactor.callLater
延迟方法。请参阅:http://twistedmatrix.com/documents/current/core/howto/time.html
我猜你的代码并没有真正等待下一个连接,但是睡眠阻止了下一个连接,直到计时器用完为止,此时你看到你的第二个连接连接并且你的第一个连接死了。
尝试reactor.callLater
代替您的定时器调用,看看是否可以解决您的问题。如果没有使用更多代码/测试示例更新您的问题
更新(...评论指出此问题为threading
而非timeit
)
鉴于Twisted的许多部分都不是线程安全的(其中“不安全”意味着任何可能发生 - 行为是不可预测的),以下只是猜测,但我认为这是对你所看到的奇怪行为的合理解释:
reactor.run
设置select
/ epoll
/周期事件调用样式的循环,只注册您的通信文件描述符以唤醒事件调用它会进入睡眠状态。timerClass
运行,但扭曲回到睡眠状态,幸福地没有意识到线程。这意味着:self.transport.abortConnection
时,会设置一些意图关闭连接的变量,但是在Twisted唤醒后才能执行这些变量后面的工作(......我的具体细节可能是在这里特别错误,我没有挖掘abortConnection
代码库,以确保这是该电话的现实)abortConnection
进程,从而终止第一个连接。该理论的测试是在线程Timer
运行transport.abortConnection
之后让第一个连接发送数据。接收数据应该唤醒Twisted,并遵循我的理论,应该让transport.abortConnection
完成而不需要第二次连接。
尽管如此,修复是一样的。切换到Twisted的reactor.callLater
,它将计时器直接注册到Twisted的事件休眠中。
如果您对Twisted vs threads的较长细分感兴趣,请参阅How to run a program and also execute code...
上的答案