简体   繁体   English

具有Twisted的交互式Python客户端/服务器

[英]Interactive Python Client/Server with Twisted

I've been trying to wrap my mind around how to get Twisted to perform, for lack of a better word, "interactive" client/server behavior. 我一直试图围绕如何让Twisted执行,因为缺乏更好的词,“交互式”客户端/服务器行为。

I managed to put together a pair of Protocol and ClientFactory classes that do connect to a service, and perform an immediate query/response (see: connectionMade -> self.queryStatus). 我设法将一对连接到服务的Protocol和ClientFactory类放在一起,并执行立即查询/响应(请参阅:connectionMade - > self.queryStatus)。 This succeeds as expected and prints the server's response from the Factory class. 这按预期成功,并从Factory类打印服务器的响应。

My problem now is that I'll have outside events that must cause data to be sent, while always listening for potential incoming data. 我现在的问题是,我将有外部事件必须导致数据被发送,同时总是侦听潜在的传入数据。 But once the reactor.run() loop is going, I'm not sure how the rest of my application is meant to trigger a data send. 但是一旦reactor.run()循环开始,我不确定我的应用程序的其余部分是如何触发数据发送的。

I've tried a few different approaches since, but this is the simplest approach that did handle the recv part as described: 我从那以后尝试过几种不同的方法,但这是处理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()

I imagine this is pretty straight-forward, but countless hours into numerous examples and documentation have left me without a good understanding of how I'm meant to deal with this scenario. 我想这很简单,但无数个小时的例子和文档让我对我如何处理这个场景没有很好的理解。

My problem now is that I'll have outside events that must cause data to be sent, while always listening for potential incoming data. 我现在的问题是,我将有外部事件必须导致数据被发送,同时总是侦听潜在的传入数据。 But once the reactor.run() loop is going, I'm not sure how the rest of my application is meant to trigger a data send. 但是一旦reactor.run()循环开始,我不确定我的应用程序的其余部分是如何触发数据发送的。

"Outside events"? “外部活动”? Like what? 像什么? Data arriving on a connection? 数据到达连接? Great, having the reactor running means you'll actually be able to handle that data. 很好,让反应堆运行意味着你实际上能够处理这些数据。

Or maybe someone is clicking a button in a GUI? 或者有人点击GUI中的按钮? Try one of the GUI integration reactors - again, you can't handle those events until you have a reactor running. 尝试使用其中一个GUI集成反应器 - 再次,在反应堆运行之前,您无法处理这些事件。

You're probably getting stuck because you think your main function should do reactor.run() and then go on to do other things . 您可能会陷入困境,因为您认为您的主要功能应该执行reactor.run()然后继续做其他事情 This isn't how it works. 这不是它的工作原理。 When you write an event-driven program, you define all of your event sources and then let the event loop call your handlers when events arrive on those sources. 编写事件驱动程序时,可以定义所有事件源,然后在事件到达这些源时让事件循环调用处理程序。

Well, there are many approaches to that, and the best one really depends on the context of your application, so I won't detail you one way of doing this here, but rather link you to a reading I had recently on hacker's news: 好吧,有很多方法,最好的方法实际上取决于你的应用程序的上下文,所以我不会在这里详细说明你这样做的一种方式,而是将你链接到我最近关于黑客新闻的阅读:

and good use-case example, though it may not apply to what you're working on (or you may have read it): 和良好的用例示例,虽然它可能不适用于您正在处理的内容(或者您可能已阅读它):

BTW, you may also have a look at gevent or tornado that are good at handling that kind of things. 顺便说一句,你也可以看看擅长处理这类事情的gevent或龙卷风。

If your other "events" are from a GUI toolkit (like GTK or QT) be really careful of the GIL , and even if you just want command line events you'll need threads and still be careful of that. 如果你的其他“事件”来自GUI工具包(比如GTK或QT),那要非常小心GIL ,即使你只是想要命令行事件,你也需要线程并且仍然要小心。

Finally, if you want to make more interaction, you may as well write different kind of "peers" for your server, that interacts with the different use cases you're working on (one client that connects to a GUI, another with a CLI, another with a database, another with a SAAS' API etc..). 最后,如果您想进行更多交互,您可以为您的服务器编写不同类型的“对等”,与您正在处理的不同用例交互(一个客户端连接到GUI,另一个客户端连接到CLI ,另一个有数据库,另一个有SAAS'API等。)。

In other words, if your design is not working, try changing your perspective! 换句话说,如果您的设计不起作用,请尝试改变您的观点!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM