[Twisted-web] Telnet chat server

Drew Smathers drew.smathers at gmail.com
Thu Jun 4 19:06:11 EDT 2009


2009/6/3 Jason St.Clair <woahyeahyeah at yahoo.com>:
> I've got a simple little chat server set up that people can telnet into.  The code is as follows:
>
> ----------
>
> from twisted.internet import reactor
> from twisted.internet.protocol import ServerFactory
> from twisted.protocols.basic import LineOnlyReceiver
> import threading
>
> class ChatProtocol(LineOnlyReceiver):
>
>     name = ""
>
>     def getName(self):
>         if self.name!="":
>             return self.name
>         return self.transport.getPeer().host
>
>     def connectionMade(self):
>         print "New connection from "+self.getName()
>         self.sendLine("Welcome to the chat.\r\n/quit to quit.")
>         self.factory.sendMessageToAllClients(self.getName()+" joined the chat.")
>         self.factory.clientProtocols.append(self)
>
>     def connectionLost(self, reason):
>         print "Lost connection from "+self.getName()
>         self.factory.clientProtocols.remove(self)
>         self.factory.sendMessageToAllClients(self.getName()+" disconnected.")
>
>     def lineReceived(self, line):
>         if line=="/quit":
>             self.transport.loseConnection()
>         else:
>             self.factory.sendMessageToAllClients(self.getName()+": "+line)
>
>     def sendLine(self, line):
>         self.transport.write(line+"\r\n")
>
> class ChatProtocolFactory(ServerFactory):
>
>     protocol = ChatProtocol
>
>     def __init__(self):
>         self.clientProtocols = []
>
>     def sendMessageToAllClients(self, mesg):
>         for client in self.clientProtocols:
>             client.sendLine(mesg)
>
> def Test():
>     global test
>     factory.sendMessageToAllClients('Hey.')
>     test = threading.Timer(1.0, Test)
>     test.start()
> test = threading.Timer(1.0, Test)
> test.start()
>
> print "Starting Server"
> factory = ChatProtocolFactory()
> reactor.listenTCP(3009, factory)
> reactor.run()
>
> ----------
>
> The problem is that last def, "def Test()".  It should send the line "Hey." to all connected users every second.  It does that - however, the message only sends through if the client is typing or has entered a line.  So, if a client is idle for 30 seconds, then starts typing, he will receive "Hey." 30 times in a row - one for each second he was idle.
>
> Is there any way to get this to send the message and have it show up for a client even when they're idle?
> _______________________________________________
> Twisted-web mailing list
> Twisted-web at twistedmatrix.com
> http://twistedmatrix.com/cgi-bin/mailman/listinfo/twisted-web
>
>

You should use twisted.internet.task.LoopingCall instead of
threading.Timer and it's also worth mentioning that twisted APIs are
*not* thread-safe; in use cases where you have to use threads (there
are really few), you should use reactor.callFromThread().

So the equivalent for the above using LoopingCall would be something like:

def test():
    factory.sendMessageToAllClients('Hey.')
task = LoopingCall(test)
reactor.callWhenRunning(task.start, 1.0, 0)
...

HTH

-Drew



More information about the Twisted-web mailing list