[Twisted-Python] using ClientFactory from within a server
I am having trouble using ClientFactory to communicate from within a server. Specifically, I can't figure out the proper way to exit from the client process. Included is some example code illustrating the problem I am having. It is the simple echo server example, but when someone sends some text to the server, I am trying to talk to an SMTP server to send an email. This is just an example (there are probably better ways to fire off an email), but you get the idea. The client code never "exits" and if I try to use reactor.stop() it causes a traceback. So how do I properly exit from this client code, or (being new to twisted) am I going about this in the entirely wrong way? Thanks. #!/usr/bin/env python from twisted.internet import reactor from twisted.internet.protocol import Protocol, ClientFactory, ServerFactory import sys class Echo(Protocol): """This is just about the simplest possible protocol""" def dataReceived(self, data): "As soon as any data is received, write it back." self.transport.write(data) factory2 = MySMTPClientFactory() host = 'localhost' port = 25 reactor.connectTCP(host, port, factory2) reactor.run() print "Returned from sending email" # ^ Never gets to this point class MySMTP(Protocol): def dataReceived(self, data): sys.stdout.write('Server said: ' + data) if data[:3] == "220": self.transport.write("helo foo.com\n") self.stage = 1 if data[:3] == "250": if self.stage == 1: self.transport.write("MAIL FROM:<greg@foo.com>\n") self.stage = 2 elif self.stage == 2: self.transport.write("RCPT TO:<greg@foo.com>\n") self.stage = 3 elif self.stage == 3: self.transport.write("DATA\n") self.stage = 4 elif self.stage == 4: self.transport.write("QUIT\n") self.transport.loseConnection() #reactor.stop() # ^ This causes a traceback if data[:3] == "354": # Ready to send actual email self.transport.write("This is a test email\n.\n") class MySMTPClientFactory(ClientFactory): def startedConnection(self, connector): print 'Started to connect.' def buildProtocol(self, addr): print 'Connected.' return MySMTP() def clientConnectionLost(self, connector, reason): print 'Lost connection. Reason:', reason #reactor.stop() # ^ Causes a traceback here too def clientConnectionFailed(self, connector, reason): print 'Connection failed. Reason:', reason def main(): """This runs the protocol on port 8000""" factory = ServerFactory() factory.protocol = Echo reactor.listenTCP(8000,factory) reactor.run() # this only runs if the module was *not* imported if __name__ == '__main__': main()
On Sun, Sep 28, 2003 at 09:30:33PM -0400, Greg wrote:
I am having trouble using ClientFactory to communicate from within a server. Specifically, I can't figure out the proper way to exit from the client process.
Included is some example code illustrating the problem I am having. It is the simple echo server example, but when someone sends some text to the server, I am trying to talk to an SMTP server to send an email. This is just an example (there are probably better ways to fire off an email), but you get the idea. The client code never "exits" and if I try to use reactor.stop() it causes a traceback.
reactor.run() enters the twisted mainloop. reactor.stop() causes the mainloop to terminate in the near future. You cannot nest calls to the mainloop (nor do you need to do so).
So how do I properly exit from this client code, or (being new to twisted) am I going about this in the entirely wrong way? Thanks.
#!/usr/bin/env python
from twisted.internet import reactor from twisted.internet.protocol import Protocol, ClientFactory, ServerFactory import sys
class Echo(Protocol): """This is just about the simplest possible protocol"""
def dataReceived(self, data): "As soon as any data is received, write it back." self.transport.write(data) factory2 = MySMTPClientFactory() host = 'localhost' port = 25 reactor.connectTCP(host, port, factory2) reactor.run()
Remove the above call to "reactor.run() and see what happens.
print "Returned from sending email" # ^ Never gets to this point
class MySMTP(Protocol): [snip]
I don't understand why you aren't using twisted.protocols.smtp.
[snip]
reactor.connectTCP(host, port, factory2) reactor.run()
Remove the above call to "reactor.run() and see what happens.
print "Returned from sending email" # ^ Never gets to this point
Thanks. Now I am getting closer. But a strange (to me) thing happens. When I connect to the Echo server and send it a string, it does correctly run the MySMTP code. But it does not return and execute the 'print "Returned from sending email"' statement until I connect to the Echo server again and send another string. Any idea why this is happening? Is there a way to disconnect factory2 from the reactor after I have sent the "QUIT" string (or when MySMTPClientFactory.clientConnectionLost() gets called)?
class MySMTP(Protocol): [snip]
I don't understand why you aren't using twisted.protocols.smtp.
The use of SMTP is just an example. In reality I'm talking a different protocol, but I wanted to use a common protocol like SMTP in my example so that someone on the list could easily test my code.
Greg wrote:
reactor.connectTCP(host, port, factory2) reactor.run()
Remove the above call to "reactor.run() and see what happens.
print "Returned from sending email" # ^ Never gets to this point
Thanks. Now I am getting closer. But a strange (to me) thing happens. When I connect to the Echo server and send it a string, it does correctly run the MySMTP code. But it does not return and execute the 'print "Returned from sending email"' statement until I connect to the Echo server again and send another string. Any idea why this is happening? Is there a way to disconnect factory2 from the reactor after I have sent the "QUIT" string (or when MySMTPClientFactory.clientConnectionLost() gets called)?
Never mind, I suck. I finally noticed that it was of course immediately returning from the reactor.connectTCP() and immediately printing "Returned from sending email", then getting around to actually running the MySMTPClientFactory stuff. I guess I have to learn about using deferreds. Thanks again for your previous help.
participants (2)
-
Greg
-
Jp Calderone