1 twisted
我是 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
Run Code Online (Sandbox Code Playgroud)
它按我的需要工作,但我确信这是非常糟糕的解决方案。我怎样才能以不同的方式(灵活和正确)做到这一点?谢谢。
PS - 主要思想和算法: 1. 客户端连接到服务器并等待 2. 服务器检查更新并将数据推送到客户端,如果有任何变化 3. 客户端执行一些操作,然后等待其他数据
在不知道您提供链接到您的internet.XXXServer或reactor.listenXXX(或XXXXEndpoint调用)的代码段的情况下,很难对其进行正面或反面,但是......
首先,在正常使用中,一个扭曲protocol.Protocol的dataReceived只会由框架调用。它将直接或通过工厂链接到客户端或服务器连接,并在数据进入给定连接时自动调用。(绝大多数twisted 协议和接口(如果不是全部)都是基于中断的,而不是轮询/callLater,这就是使Twisted 如此CPU 高效的部分原因)
因此,如果您显示的代码实际上通过 a Serveror listenor链接到 TwistedEndpoint到您的客户,那么我认为如果您的客户发送数据,您会发现会发生非常糟糕的事情(...因为twisted 会要求dataReceived这样做,其中(以及其他问题) ) 会增加额外的reactor.callLater回调,随之而来的是各种混乱......)
相反,如果代码没有链接到扭曲连接框架,那么您试图在它们不是设计的空间中重用扭曲类(......我想这似乎不太可能,因为我不知道非连接代码如何将了解传输,除非您手动设置它......)
我一直在构建这样的构建模型的方式是为基于轮询的 I/O 创建一个完全独立的类,但是在我实例化它之后,我将我的客户端列表(服务器)工厂推送到轮询实例中(类似于mypollingthing.servfact = myserverfactory)从而让我的轮询逻辑能够调用客户端 .write(或者更可能是我构建的一个 def,用于抽象到我的轮询逻辑的正确级别)
我倾向于将 Krondo 的Twisted Introduction中的示例作为如何进行扭曲(其他扭曲矩阵)的规范示例之一,第 6 部分中的示例在“客户端 3.0”下PoetryClientFactory有一个__init__在工厂中设置回调的示例。
如果我尝试将其与twistedmatrix 聊天示例和其他一些内容混合在一起,我会得到:(您将想要更改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()
Run Code Online (Sandbox Code Playgroud)
公平地说,最好PollingIOThingy通过将回调作为参数传递给它来通知回调__init__(这就是 Krondo 的文档中显示的内容),出于某种原因,我在阅读代码和查找类时往往会错过这样的连接-作弊更容易看到,但这可能只是我个人的脑损伤。