【问题标题】:Interactive Python Client/Server with Twisted带有 Twisted 的交互式 Python 客户端/服务器
【发布时间】:2013-05-31 04:47:35
【问题描述】:

我一直在努力思考如何让 Twisted 执行,因为没有更好的词,“交互式”客户端/服务器行为。

我设法将一对确实连接到服务的 Protocol 和 ClientFactory 类放在一起,并执行即时查询/响应(请参阅:connectionMade -> self.queryStatus)。这按预期成功并打印了来自 Factory 类的服务器响应。

我现在的问题是,我将有必须导致数据发送的外部事件,同时始终侦听潜在的传入数据。但是一旦 reactor.run() 循环开始,我不确定我的应用程序的其余部分是如何触发数据发送的。

从那以后我尝试了几种不同的方法,但这是处理所述 recv 部分的最简单方法:

class myListenerProtocol(LineReceiver):
    delimiter = '\n'

    def connectionMade(self):
        print("Connected to: %s" % self.transport.getPeer())
        self.queryStatus(1)

    def dataReceived(self, data):
        print("Receiving Data from %s" % self.transport.getPeer())
        ...
        self.commandReceived(self.myData)

    def commandReceived(self, myData):
        self.factory.commandReceived(myData)

    def connectionLost(self, reason):
        print("Disconnected.")

    def queryStatus(self, CommandValue):
        ...
        strSend = CommandValue # or some such
        self.transport.write(strSend)

class mySocketFactory(ClientFactory):
    protocol = myListenerProtocol

    def __init__(self):
        pass

    def buildProtocol(self, address):
        proto = ClientFactory.buildProtocol(self, address)
        return proto

    def commandReceived(self, myData):
        print myData
        reactor.stop() # It won't normally stop after recv

    def clientConnectionFailed(self, connector, reason):
        print("Connection failed.")
        reactor.stop()


def main():
    f = mySocketFactory()
    reactor.connectTCP("10.10.10.1", 1234, f)
    reactor.run()

我想这很简单,但无数小时的大量示例和文档让我无法很好地理解我应该如何处理这种情况。

【问题讨论】:

    标签: python twisted


    【解决方案1】:

    我现在的问题是,我将有必须导致数据发送的外部事件,同时始终侦听潜在的传入数据。但是一旦 reactor.run() 循环开始,我不确定我的应用程序的其余部分是如何触发数据发送的。

    “外部事件”?像什么?数据到达连接?太好了,让反应堆运行意味着您实际上可以处理这些数据。

    或者也许有人正在单击 GUI 中的按钮?尝试其中一个 GUI 集成反应器 - 再一次,在反应器运行之前,您无法处理这些事件。

    您可能会卡住,因为您认为您的主要功能应该做reactor.run() 然后继续做其他事情。这不是它的工作方式。当您编写事件驱动程序时,您定义了所有事件源,然后在事件到达这些源时让事件循环调用您的处理程序。

    【讨论】:

    • 不,我的意思是我将把它作为一个更大的应用程序的一个组件。例如,假设它是一个在后台运行、连接的客户端组件,而您正在使用主要的 GUI 驱动应用程序。因此,在主(现有)应用程序中发生了一个事件。不管是什么触发它,但它会导致这个连接的客户端会话发送数据。同时,它将接受传入的连接,我必须处理这些。
    • 触发它的原因很重要,因为这将决定您如何集成不同的组件。如果您想完全忽略其他组件的实现方式,请在单独的进程中运行它们并使用某种 IPC/RPC。这通常需要更多的工作,但如果您根本不想指定每个组件的实现方式,这是使两个组件协同工作的最直接的方法。
    • 如果不清楚,我认为您应该只需指定其他组件的工作方式,然后弄清楚如何将其集成到 Twisted 事件循环中。上面的评论是为了以防你不这样做。
    【解决方案2】:

    嗯,有很多方法可以做到这一点,最好的方法实际上取决于您的应用程序的上下文,所以我不会在这里详细介绍一种方法,而是将您链接到我最近阅读的一篇文章黑客新闻:

    以及很好的用例示例,尽管它可能不适用于您正在从事的工作(或者您可能已经阅读过):

    顺便说一句,你也可以看看擅长处理这类事情的 gevent 或 tornado。

    如果您的其他“事件”来自 GUI 工具包(如 GTK 或 QT),请真正小心 GIL,即使您只需要命令行事件你需要线程并且仍然要小心。

    最后,如果您想进行更多交互,您不妨为您的服务器编写不同类型的“对等点”,它们与您正在处理的不同用例交互(一个连接到 GUI 的客户端,另一个使用 CLI,另一个使用数据库,另一个使用 SAAS 的 API 等。)。

    换句话说,如果您的设计不起作用,请尝试改变您的观点!

    【讨论】:

    • 您不必小心 GIL。只是不要使用线程。这篇文章没有任何暗示需要线程,所以 GIL 是无关紧要的。
    猜你喜欢
    • 2013-12-24
    • 1970-01-01
    • 2015-12-25
    • 2013-07-30
    • 2016-07-28
    • 1970-01-01
    • 2012-04-08
    • 2013-10-27
    • 2011-04-07
    相关资源
    最近更新 更多