Search code examples
pythonnetwork-programmingsocketstcptwisted

Twisted ignoring data sent from MUD Clients?


I have the following code (almost an exact copy of the Chat server example listed here:

import twisted.scripts.twistd from twisted.protocols import basic from twisted.internet import protocol, reactor from twisted.application import service, internet

class MyChat(basic.LineReceiver):
    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)

    def lineReceived(self, line):
        print "received", repr(line)
        for c in self.factory.clients:
            c.message(line)

    def message(self, message):
        self.transport.write(message + '\n')

factory = protocol.ServerFactory()
factory.protocol = MyChat
factory.clients = []

if __name__ == "__main__":
    print "Building reactor...."
    reactor.listenTCP(50000, factory)
    print "Running ractor...."
    reactor.run()
else:
    application = service.Application("chatserver")
    internet.TCPServer(50000, factory).setServiceParent(application)

The server runs without error, and if I connect to it via Telnet, I can send data and the server prints to the console and relays it to all clients (as is expected). However, if I connect to it via a different tool (a MUD client), it never gets the data.

I have ensured that the client is sending the data (Traced the packets with Wireshark, and they're going across the wire), but the server either never receives it, or is choosing to ignore it for some reason.

I have tried this with two MUD clients, gmud, and JMC. If it is important, I am running Windows 7 x64.

Does anyone have any idea why this could be happening?

Thanks,

Mike

EDIT:

Thanks to the hints provided by Maiku Mori, I tried adding another method that was specified in the Twisted API Docs, dataReceived. Once this was added, the MUD clients worked perfectly, but Telnet is now sending every character as it's own set of data, instead of waiting for the user to press Enter.

Here's a snipped of the new code:

    def dataReceived(self, data):
        print "Dreceived", repr(data)
        for c in self.factory.clients:
            c.message(data)

#    def lineReceived(self, line):
#        print "received", repr(line)
#        for c in self.factory.clients:
#            c.message(line)

Has anyone experiences this before, and if so, how do you get around it? Ideally, I would like Telnet and MUD clients to work with this application.

Thanks again.


Solution

  • In case anyone stumbles across this question with similar problems, I'm leaving my findings as the accepted answer so that people don't have to hunt the way I did.

    I fixed the issue by changing the delimiter value from in my Twisted protocol from "\r\n" (default), to just "\n" (which is what my MUD clients send. This means that in Telnet, when you enter the string:

    Hello, World
    

    Your application will receive it as:

    Hello, World\r
    

    You may need to do data sanitation on the server side to keep things in order. My final code was as follows:

    import twisted.scripts.twistd from twisted.protocols import basic from twisted.internet import protocol, reactor from twisted.application import service, internet

    class MyChat(basic.LineReceiver):
        def __init__(self):
            self.delimiter = "\n"
    
        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)
    
        def lineReceived(self, line):
            print "received", repr(line)
            for c in self.factory.clients:
                c.message(line)
    
        def message(self, message):
            self.transport.write(message + '\n')
    
    factory = protocol.ServerFactory()
    factory.protocol = MyChat
    factory.clients = []
    
    if __name__ == "__main__":
        print "Building reactor...."
        reactor.listenTCP(50000, factory)
        print "Running ractor...."
        reactor.run()
    else:
        application = service.Application("chatserver")
        internet.TCPServer(50000, factory).setServiceParent(application)
    

    Thanks for all the help.