使用任务循环调用从工厂会话外部向所有客户端发送数据

Twisted Send Data to all Clients from Outside the Factory sessions with task Looping Call

我正在尝试解决一个简单的 Twisted 问题。

为了简单起见,我使用 Python 2.7 Twisted Chat.py 示例。

from twisted.internet.protocol import Factory
from twisted.protocols.basic import LineReceiver
from twisted.internet import reactor

class Chat(LineReceiver):

    def __init__(self, users):
        self.users = users
        self.name = None
        self.state = "GETNAME"

    def connectionMade(self):
        self.sendLine("What's your name?")

    def connectionLost(self, reason):
        if self.users.has_key(self.name):
            del self.users[self.name]

    def lineReceived(self, line):
        if self.state == "GETNAME":
            self.handle_GETNAME(line)
        else:
            self.handle_CHAT(line)

    def handle_GETNAME(self, name):
        if self.users.has_key(name):
            self.sendLine("Name taken, please choose another.")
            return
        self.sendLine("Welcome, %s!" % (name,))
        self.name = name
        self.users[name] = self
        self.state = "CHAT"

    def handle_CHAT(self, message):
        message = "<%s> %s" % (self.name, message)
        for name, protocol in self.users.iteritems():
            if protocol != self:
                protocol.sendLine(message)


class ChatFactory(Factory):

    def __init__(self):
        self.users = {} # maps user names to Chat instances

    def buildProtocol(self, addr):
        return Chat(self.users)


reactor.listenTCP(8123, ChatFactory())
reactor.run()

我想做的是使用 twisted.internet 任务创建一个每 60 秒运行一次并将数据发送到所有连接会话的任务。

半伪代码

def broadcastmsg():
    for client in factory:
        client.protocol.transport.write("I am a Test\n\r")

event = task.LoopingCall(broadcastmsg)
event.start(60) 

问题是我无法让 Twisted 正常运行。我可以在每个会话的基础上实现它。但是每次连接它都会发送两倍的垃圾邮件等等。

您如何设置循环通话?

如您所知,协议是由工厂创建和管理的。定期向所有用户发送一些消息看起来像是一项应该放入工厂的任务。您可以在 factory __init__ 方法中创建 loopingCall 并在 init 之后立即启动它。由于每个连接都有一个工厂,这应该每 60 秒只发送一次通知

class ChatFactory(Factory):

    def __init__(self):
        self.users = {} # maps user names to Chat instances

        def broadcast_msg():
            for name in self.users:
                self.users[name].sendLine("looping call send to users: {}".format(self.users.keys()))

        self.looping_call = task.LoopingCall(broadcast_msg)
        self.looping_call.start(60)

这应该没问题,至少对我来说是这样。