I am looking for a way to periodically send some data over all clients connected to a TCP port. I am looking at twisted python and I am aware of reactor.callLater. But how do I use it to send some data to all connected clients periodically ? The data sending logic is in Protocol class and it is instantiated by the reactor as needed. I don't know how to tie it from reactor to all protocol instances...
2 Answers
You would probably want to do this in the Factory for the connections. The Factory is not automatically notified of every time a connection is made and lost, so you can notify it from the Protocol.
Here is a complete example of how to use twisted.internet.task.LoopingCall in conjunction with a customised basic Factory and Protocol to announce that '10 seconds has passed' to every connection every 10 seconds.
from twisted.internet import reactor, protocol, task
class MyProtocol(protocol.Protocol):
def connectionMade(self):
self.factory.clientConnectionMade(self)
def connectionLost(self, reason):
self.factory.clientConnectionLost(self)
class MyFactory(protocol.Factory):
protocol = MyProtocol
def __init__(self):
self.clients = []
self.lc = task.LoopingCall(self.announce)
self.lc.start(10)
def announce(self):
for client in self.clients:
client.transport.write("10 seconds has passed\n")
def clientConnectionMade(self, client):
self.clients.append(client)
def clientConnectionLost(self, client):
self.clients.remove(client)
myfactory = MyFactory()
reactor.listenTCP(9000, myfactory)
reactor.run()

- 41,746
- 15
- 73
- 90
-
Thanks! This helped a lot. I was trying to handle sending the data in the protocol class and was having problems dealing with not having access to all clients (had a singleton class to hold them all!)! Doing this in the factory subclass makes so much more sense. I'll rewrite my code... Thanks! – Amit Nov 25 '08 at 20:18
-
How would you write a test to verify that a client gets "*10 seconds has passed\n*" six times in a minute? – Sardathrion - against SE abuse Jan 31 '13 at 11:39
I'd imagine the easiest way to do that is to manage a list of clients in the protocol with connectionMade and connectionLost in the client and then use a LoopingCall to ask each client to send data.
That feels a little invasive, but I don't think you'd want to do it without the protocol having some control over the transmission/reception. Of course, I'd have to see your code to really know how it'd fit in well. Got a github link? :)

- 89,080
- 21
- 111
- 133
-
I got the initial version working. The reactor.callLater can be called anywhere, so I ended up calling it from connectionMade(). However, now the problem is that every connection gets it's own timer and data. I would really like a single timer and data. (like a broadcast)... – Amit Nov 25 '08 at 02:49