2014-04-24 174 views
0

我是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 

它的工作原理我是如何,但我敢肯定,这是很糟糕的解决方案。我如何以不同的方式做到这一点(灵活和正确)?谢谢。

P.S. - 主要思路和alghorithm: 1.客户端连接到服务器,并等待 2.服务器检查更新和将数据推送到客户端,如果有什么变化 3.客户做一些操作,然后等待其他数据

+0

除了其他任何东西,你真的不应该像这样调用'dataReceived'。如果你把这个逻辑放到一个没有*已经*有一些(不同的,不兼容的)含义的方法中,那么代码就可以工作。 –

回答

2

不知道您提供的链接到您的internet.XXXServerreactor.listenXXX(或XXXXEndpoint调用)的片段,其难如何使头部或尾巴的,但...

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

因此,如果你显示的代码实际上通过ServerlistenEndpoint给你的客户,那么我认为你会发现如果你的客户发送数据会发生非常糟糕的事情(...因为扭曲会调用dataReceived,其中(除其他问题外)将增加额外的reactor.callLater回调和各种的混乱将随之而来...)

如果相反,代码没有链接到扭曲连接框架,那么你试图重用扭曲的类在一个空间,他们是不是为( ...我猜这似乎不太可能,因为我不知道非连接代码如何学习交通工具,除非您手动设置它...)

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

我倾向于将Krondo的Twisted Introduction中的示例作为一个典型示例做扭曲(然后扭曲的矩阵),并在的例子,在“客户端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() 

说句公道话,它可能最好是通知PollingIOThingy,将它作为参数传递给__init__(这正是Krondo的文档中所示的内容)。由于某些原因,当我阅读代码并发现类欺骗更容易时,我倾向于错过这样的连接看,但这可能只是我个人的脑损伤。

+0

迈克,非常感谢你!它真的是我想要的,我无法理解。非常感谢!!! – inhibitor

+0

很高兴帮助!顺便说一句,如果它与您的问题相匹配,请将我的帖子标记为答案。 –