第一个是仅在第二个客户端连接时才断开连接

时间:2014-06-28 11:52:45

标签: python-2.7 twisted

我有以下代码的扭曲服务器监听客户端

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秒后没有断开连接,它在第二个客户端连接到服务器后断开连接。为什么会这样发生,我不敢弄明白。

1 个答案:

答案 0 :(得分:1)

向我跳出来的是你的Timer电话,来自哪里?它是timeit.Timer

它向我跳出来的原因是,如果你阻挡反应堆,Twisted的行为会变得一团糟,除非我错了,这个叫声是一个阻塞的睡眠。 (我也发现一些线程timer调用的参考,这也可能导致扭曲的麻烦,因为大部分扭曲不是线程安全的,所以以下答案仍然适用)

通常在Twisted中,您希望对此应用程序样式使用reactor.callLater延迟方法。请参阅:http://twistedmatrix.com/documents/current/core/howto/time.html

我猜你的代码并没有真正等待下一个连接,但是睡眠阻止了下一个连接,直到计时器用完为止,此时你看到你的第二个连接连接并且你的第一个连接死了。

尝试reactor.callLater代替您的定时器调用,看看是否可以解决您的问题。如果没有使用更多代码/测试示例更新您的问题

更新(...评论指出此问题为threading而非timeit

鉴于Twisted的许多部分都不是线程安全的(其中“不安全”意味着任何可能发生 - 行为是不可预测的),以下只是猜测,但我认为这是对你所看到的奇怪行为的合理解释:

  1. 您的reactor.run设置select / epoll /周期事件调用样式的循环,只注册您的通信文件描述符以唤醒事件调用它会进入睡眠状态。
  2. 你的第一个连接进来了,它瞬间醒来扭曲为服务连接,你的timerClass运行,但扭曲回到睡眠状态,幸福地没有意识到线程。这意味着:
  3. 当你的线程睡眠完成并运行self.transport.abortConnection时,会设置一些意图关闭连接的变量,但是在Twisted唤醒后才能执行这些变量后面的工作(......我的具体细节可能是在这里特别错误,我没有挖掘abortConnection代码库,以确保这是该电话的现实)
  4. 一切都被卡住,直到Twisted唤醒,但这只会发生在事件中,例如:
  5. 您建立第二个连接,唤醒Twisted事件调用
  6. 再次使用Twisted唤醒,可以完成在线程调用中启动的abortConnection进程,从而终止第一个连接。
  7. 该理论的测试是在线程Timer运行transport.abortConnection之后让第一个连接发送数据。接收数据应该唤醒Twisted,并遵循我的理论,应该让transport.abortConnection完成而不需要第二次连接。

    尽管如此,修复是一样的。切换到Twisted的reactor.callLater,它将计时器直接注册到Twisted的事件休眠中。

    如果您对Twisted vs threads的较长细分感兴趣,请参阅How to run a program and also execute code...

    上的答案