我是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。 - 主要思想和算法: 1.客户端连接到服务器并等待 2.如果有任何更改,服务器会检查更新并将数据推送到客户端 3.客户端执行某些操作,然后等待其他数据
答案 0 :(得分:2)
在不知道您提供的代码段如何链接到internet.XXXServer
或reactor.listenXXX
(或XXXXEndpoint
来电)的情况下,很难做到这一点,但......
首先,在正常使用中,扭曲的protocol.Protocol
' dataReceived
只会被框架本身调用。它将直接或通过工厂链接到客户端或服务器连接,并且当数据进入给定连接时将自动调用它。 (绝大多数的双绞线协议和接口(如果不是全部)都是基于中断的,而不是轮询/ callLater,这是使Twisted如此高效的部分原因)
因此,如果您显示的代码实际上通过Server
或listen
或Endpoint
链接到Twisted给您的客户,那么我认为如果您的客户曾经发现过非常糟糕的事情会发生发送数据(...因为twisted会为此调用dataReceived
,这会(除其他问题之外)会添加额外的reactor.callLater
回调,并且会发生各种混乱......)
如果相反,代码没有链接到扭曲的连接框架,那么你试图在一个他们没有设计的空间中重用扭曲的类(...我想这似乎不太可能,因为我不&# 39;知道非连接代码如何学习传输,除非你手动设置它......)
我构建这样的模型的方式是为基于轮询的I / O创建一个完全独立的类,但在实例化之后,我将我的客户列表(服务器)工厂推送到轮询中实例(类似于mypollingthing.servfact = myserverfactory
) - 通过为我的轮询逻辑提供一种方法来调用客户端.write(或者更可能是我构建的def以抽象到我的轮询逻辑的正确级别)< / p>
我倾向于将Krondo的Twisted Introduction中的示例作为如何进行扭曲(除了扭曲矩阵之外)的典型示例之一,以及part 6中的示例,在&{ #34;客户端3.0&#34; 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
作为一个arg传递给它__init__
来告知{{1}}(这是Krondo&#39;中显示的内容)。 docs),出于某种原因,当我阅读代码并发现类作弊更容易看到时,我倾向于错过这样的连接,但这可能只是由于我个人的脑损伤。