Twisted: How to sendLine from outside the LineReceiver class?

Andrew Bennetts andrew-pythonlist at puzzling.org
Sun Feb 29 19:51:49 EST 2004


[You'll probably get more answers to Twisted questions on the Twisted
mailing-list: twisted-python at twistedmatrix.com]

On Sun, Feb 29, 2004 at 02:06:07PM -0500, Qp wrote:
> Hello.  I'm building a simple chat server and client interface, and I've got
> everything working except for this:
> 
> While the client's basic.LineReceiver protocol class can sendLine when a
> connection is made (that is, when the class is called automatically),
> whenever I try to call sendLine from another class (my ClientFactory class)
> then I get the following error.
> 
> "in sendLine
> return self.transport.write(line + self.delimiter)
> AttributeError: 'NoneType' object has no attribute 'write'"
> 
> So, I assume the instance of the LineReceiver is not set up properly.  How
> do I do this?
> 
> The code I am using for the classes is as follows.  The error comes when I
> call chatFactory.sendMessage():
> 
[...]
> class chatFactory(protocol.ClientFactory):
>     protocol = chatClient
> 
[...]
>     def sendMessage(self):
>         c = chatClient()
>         c.sendLine("Hey there")

I see you are using ClientFactory, so I presume you want to make a client
connection to a remote server with this protocol.

You need to connect your protocol, not just create the object out of thin
air.  See:

    http://twistedmatrix.com/documents/howto/clients

and also:

    http://twistedmatrix.com/documents/current/api/twisted.internet.interfaces.IReactorTCP.html#connectTCP

I think the easiest way to do what you need is to have the protocol's
connectionMade signal the factory:

----
class ChatClient(basic.LineReceiver):

    def connectionMade(self):
        self.sendLine("A new person has entered the room!")
        self.factory.clientReady(self)

    def lineReceived(self, line):
        app.text_output.config(state=NORMAL) #enable text_output for insert
        app.text_output.insert(END, line +"\n")
        app.text_output.config(state=DISABLED)
        app.text_input.delete(0, END) #clear text_input
        app.text_output.see(END) #move scrollbar to the bottom

    def connectionLost(self, reason):
        reactor.stop()

class ChatFactory(protocol.ClientFactory):
    protocol = ChatClient

    def clientConnectionFailed(self, connector, reason):
        reactor.stop()

    def clientConnectionLost(self, connector, reason):
        reactor.stop()

    def startFactory(self):
        self.messageQueue = []
        self.clientInstance = None

    def clientReady(self, instance):
        self.clientInstance = instance
        for msg in self.messageQueue:
            self.sendMessage(msg)

    def sendMessage(self, msg='Hey there'):
        if self.clientInstance is not None:
            self.clientInstance.sendLine(msg)
        else:
            self.messageQueue.append(msg)
----

Note that I've added a simple message queue because it may take some time
for the connection to be established, so calls to sendMessage could fail if
called too soon.  The queue avoids that problem.

A better solution might be to not write the factory at all, and use
twisted.internet.protocol.clientCreator:

    http://twistedmatrix.com/documents/current/api/twisted.internet.protocol.ClientCreator.html

----
from twisted.python import log

# Create creator and connect
clientCreator = protocol.ClientCreator(reactor, ChatClient)
deferred = clientCreator.connectTCP(host, port)

# When connected, send a line
def connectionReady(protocol):
    protocol.sendLine('Hey there')
deferred.addCallback(connectionReady)

# Log any errors that occur (such as connection failed)
deferred.addErrback(log.err)
----

-Andrew.





More information about the Python-list mailing list