Python DevCenter
oreilly.comSafari Books Online.Conferences.

advertisement


Untwisting Python Network Programming
Pages: 1, 2, 3

Conducting Telnet with telnetlib

The Apache James mail server comes with a batch file to start it. As a convenient option, the example program can invoke the batch file via a call to os.system.



def start():
    print "Starting server...",
    os.system("c:/apps/bin/james.bat")
    print "done."

def stop(host):
    import telnetlib
    print "Stoping server...",

    telnet = telnetlib.Telnet(host, 4555)
    telnet.read_until("Login id:")
    telnet.write("root\n")
    telnet.read_until("Password:")
    telnet.write("root\n")
    telnet.read_until("Welcome")
    telnet.write("shutdown\n")
    telnet.close()

    print "done."

Shutting down the server, on the other hand, requires a Telnet session. Manually, you can do it through a Telnet client program connected to port 4555 of the server. Enter the user name as root, password as root, and the command shutdown, respectively. To shutdown the server programmatically in Python, use class Telnet from the core module telnetlib.

To establish a Telnet session, create a Telnet object with the Telnet server address and port number specified. To interact with the telnet server, interleave calls to methods read_until and write. The read_until method reads data from the server until it receives a specified string, while the write method sends a string to the server. Note that the Apache James mail server expects a trailing carriage return in the string from the Telnet client, so the example appends "\n" to the end of the parameter to write. The Telnet session ends with the invocation of method close on the Telnet object.

The Twisted Framework

Beyond the core Python modules, Twisted is a networking framework in a different style. As demonstrated in the previous example, Python's core networking modules use a procedural approach. To perform a task, your code must invoke a method that holds the thread of execution until the task either completes successfully or fails. Such a method is straightforward to use since it is synchronous and communicates any results of execution to its caller by means of some return value. The code to perform a sequence of tasks simply invokes the appropriate methods one by one, possibly with some structural constructs and checking of return values.

On the other hand, the Twisted framework adopts a different approach of asynchronous invocation. A method call will schedule a task to do in the framework's execution thread, returning control to its caller immediately and before the completion of the task. An event-driven mechanism communicates the results of the execution. The object returned by the asynchronous method call can register success and failure callbacks that will be invoked when the scheduled task completes successfully and fails, respectively. Performing a sequence of tasks is relatively more complex, since you must typically define each task in a method registered as the success callback to the object returned by the previous task's method.

In Twisted, get used to receiving a Deferred (from twisted.internet.defer) object from an asynchronous method call. There is also a DeferredList object which can watch for asynchronous method calls completing or failing. The engine reactor (from twisted.internet) controls the framework's execution thread. Start it and shut it down with the methods run and stop, respectively.

Sending Mails the Twisted Way

The sendmail (from twisted.mail.smtp) method is the workhorse for sending mails in Twisted. It takes similar parameters as the sendmail method of a smtplib.SMTP object, with the additional first parameter of the SMTP host name. The return value is a Deferred object to which you can attach success and failure callback methods.

def sendMail(host, addr, to, subject, content):
    from twisted.mail.smtp import sendmail
    from email.MIMEText import MIMEText

    print "Sending mail from", addr, "to", to, "..."
    msg = MIMEText(content)

    msg["Subject"] = subject
    msg["From"]    = addr
    msg["To"]      = to

    return sendmail(host, addr, [to], msg.as_string())

def main():
    ...
    elif "s" == sys.argv[1]:
        print len(addrs), "messages to be sent."
        dlist = []

        for addr in addrs:
            toaddr = user + "@" + host
            text   = "Test mail: " + addr + " to " + toaddr
            dlist.append( sendMail(host, addr, toaddr, text, text) )

        DeferredList(dlist).addBoth(lambda _: reactor.stop())
        reactor.run()

To send more than one mails with sendmail, you don't need to attach the callbacks to each of the returned Deferreds. Instead, put the Deferreds in a list to create a DeferredList object. The code then attaches a callback to that single DeferredList object via its addBoth method. It will fire when all the sendmail actions succeed or any of them fails. The callback simply stops the Twisted's execution thread by reactor.stop(). Note that the tasks scheduled or registered by sendmail or addBoth are not executing until the call to reactor.run(), which starts Twisted's execution thread.

Pages: 1, 2, 3

Next Pagearrow





Sponsored by: