【问题标题】:Persistent connection in twisted扭曲中的持久连接
【发布时间】:2014-06-09 13:03:34
【问题描述】:

我是 Twisted 的新手,有一个问题。如何在 Twisted 中组织持久连接?我有一个队列,每一秒都会检查它。如果有一些 - 在客户端发送。我找不到比每秒调用 dataReceived 更好的东西了。 协议实现代码如下:

class SyncProtocol(protocol.Protocol):
    # ... some code here
    def dataReceived(self, data):
        if(self.orders_queue.has_new_orders()):
            for order in self.orders_queue:
                self.transport.write(str(order))

        reactor.callLater(1, self.dataReceived, data)  # 1 second delay

它按我的需要工作,但我确信这是一个非常糟糕的解决方案。我怎样才能以不同的方式(灵活和正确)做到这一点?谢谢。

附: - 主要思想和算法: 1.客户端连接服务器并等待 2. 服务器检查更新并在有任何变化时将数据推送到客户端 3.客户端做一些操作,然后等待其他数据

【问题讨论】:

  • 除此之外,你真的真的真的不应该像这样打电话给dataReceived。如果您将此逻辑放入一个已经具有某些(不同的、不兼容的)含义的方法中,该代码也可以正常工作。

标签: twisted


【解决方案1】:

在不知道您提供的 sn-p 是如何链接到您的 internet.XXXServerreactor.listenXXX(或 XXXXEndpoint 调用)的情况下,很难对其进行正面或反面,但是...

首先,在正常使用中,扭曲的protocol.ProtocoldataReceived 只会被框架本身调用。它将直接或通过工厂链接到客户端或服务器连接,并在数据进入给定连接时自动调用。 (绝大多数 Twisted 协议和接口(如果不是全部)都是基于中断的,而不是 polling/callLater,这是 Twisted 如此 CPU 高效的部分原因)

因此,如果您显示的代码实际上通过 ServerlistenEndpoint 链接到 Twisted 给您的客户,那么我认为如果您的客户发送数据(...因为twisted 会为此调用dataReceived,这(除其他问题外)会增加额外的reactor.callLater 回调,然后会出现各种混乱......)

如果相反,代码没有链接到扭曲连接框架,那么您尝试在它们不是为它们设计的空间中重用扭曲类(......我想这似乎不太可能,因为我不知道如何非- 连接代码将学习传输,除非您手动设置它...)

我一直在构建这样的构建模型的方式是为基于轮询的 I/O 创建一个完全独立的类,但是在实例化它之后,我将我的客户端列表(服务器)工厂推送到轮询实例中(类似mypollingthing.servfact = myserverfactory) 之类的东西——通过让我的轮询逻辑能够调用客户端 .write (或者更可能是我为我的轮询逻辑抽象到正确级别而构建的定义)

我倾向于将 Krondo 的 Twisted Introduction 中的示例作为如何进行扭曲(其他扭曲矩阵)的典型示例之一,而 part 6 中的示例在“客户端 3.0”下 PoetryClientFactory 有一个__init__ 在工厂中设置回调。

如果我尝试将其与 twistedmatrix chat example 和其他一些东西混合,我会得到: (您需要将sendToAll 更改为您的self.orders_queue.has_new_orders() 的含义)

#!/usr/bin/python

from twisted.internet import task
from twisted.internet import reactor
from twisted.internet.protocol import Protocol, ServerFactory

class PollingIOThingy(object):
    def __init__(self):
        self.sendingcallback = None # Note I'm pushing sendToAll into here in main
        self.iotries = 0

    def pollingtry(self):
        self.iotries += 1
        print "Polling runs: " + str(self.iotries)
        if self.sendingcallback:
            self.sendingcallback("Polling runs: " + str(self.iotries) + "\n")

class MyClientConnections(Protocol):
    def connectionMade(self):
        print "Got new client!"
        self.factory.clients.append(self)

    def connectionLost(self, reason):
        print "Lost a client!"
        self.factory.clients.remove(self)

class MyServerFactory(ServerFactory):
    protocol = MyClientConnections

    def __init__(self):
        self.clients = []

    def sendToAll(self, message):
      for c in self.clients:
        c.transport.write(message)

def main():
    client_connection_factory = MyServerFactory()

    polling_stuff = PollingIOThingy()

    # the following line is what this example is all about:
    polling_stuff.sendingcallback = client_connection_factory.sendToAll
    # push the client connections send def into my polling class

    # if you want to run something ever second (instead of 1 second after
    # the end of your last code run, which could vary) do:
    l = task.LoopingCall(polling_stuff.pollingtry)
    l.start(1.0) 
    # from: https://twistedmatrix.com/documents/12.3.0/core/howto/time.html

    reactor.listenTCP(5000, client_connection_factory)
    reactor.run()

if __name__ == '__main__':
  main()

公平地说,最好通过将回调作为 arg 传递给它的 __init__ 来通知 PollingIOThingy 回调(这就是 Krondo 的文档中显示的内容),出于某种原因,我倾向于错过连接当我阅读代码并发现课堂作弊更容易看到时,就像这样,但这可能只是我个人的脑损伤。

【讨论】:

  • 迈克,非常感谢!它真的是我想要的和我无法理解的。非常感谢!!!
  • 很高兴为您提供帮助!顺便说一句,如果它与您的问题匹配,请将我的帖子标记为答案。
  • 嘿迈克,谢谢你的好答案。但是,我仍然想知道如何将消息从客户端手动发送到服务器(例如,通过按下 GUI 中的按钮等)。根据我的理解,我必须多次调用 reactor.run() ......(这是不允许的!)很高兴你能提供答案here
  • 嗨@sqp_125!如果键盘输入是您所追求的(不确定您的意思是“GUI 中的按钮”),我在其他一些 SO 回复中有示例,例如:stackoverflow.com/questions/30397425/…
  • @sqp_125 我没有 pyqt5 的直接经验,但谷歌搜索它看起来可能有自己的事件循环 - 如果这是真的,你如何将它与扭曲的集成?你在使用github.com/sunu/qt5reactor 之类的东西吗? - 正如你所指出的,你不能有多个 reactor.run() - 所以解决方案是将所有内容集成到一个事件循环(AKA reactor)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-01-11
  • 2012-08-11
  • 2015-12-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多