A guide to Getting started with the twisted framework under Python

Source: Internet
Author: User
Tags sha1 sha1 hash syslog ssh server
What is twisted?

Twisted is an event-driven network framework written in the Python language that supports a wide range of protocols, including UDP,TCP,TLS and other application-layer protocols, such as Http,smtp,nntm,irc,xmpp/jabber. The very good thing is that the twisted implementation and many application layer protocols, developers can directly only use these protocols implementation. In fact, to modify the twisted SSH server-side implementation is very simple. Many times, developers need to implement the Protocol class.

A twisted program consists of a main loop initiated by reactor and some callback functions. When an event occurs, such as when a client is connected to the server, the server-side event is triggered to execute.
Write a simple TCP server with twisted

The following code is a TCPServer, which records the data sent by the client.

= = code1.py ====import sysfrom twisted.internet.protocol import serverfactoryfrom twisted.protocols.basic Import  Linereceiverfrom Twisted.python Import logfrom twisted.internet import Reactorclass cmdprotocol (LineReceiver): delimiter = ' \ n ' def connectionmade (self): Self.client_ip = Self.transport.getPeer () [1] log.msg ("Client connection From%s "% self.client_ip) if Len (self.factory.clients) >= self.factory.clients_max:log.msg (" Too many Connecti Ons.      Bye! ") Self.client_ip = None self.transport.loseConnection () else:self.factory.clients.append (SELF.CLIENT_IP) def Connectionlost (self, Reason): Log.msg (' Lost client connection. Reason:%s '% Reason) if Self.client_ip:self.factory.clients.remove (SELF.CLIENT_IP) def linereceived (self, line)  : Log.msg (' CMD received from%s:%s '% (self.client_ip, line)) class MyFactory (serverfactory): protocol = Cmdprotocol def __init__ (self, clients_max=10): Self.clients_max = Clients_max self.clients = []log.startlogging (sys.stdout) reactor.listentcp (9999, myfactory (2)) Reactor.run () 

The following code is critical:

From twisted.internet import Reactorreactor.run ()

These two lines of code will start the Reator main loop.

In the code above we created the "Serverfactory" class, which is responsible for returning an instance of "Cmdprotocol". Each connection is handled by an instantiated "Cmdprotocol" instance. Twisted reactor automatically creates an instance of Cmdprotocol after a TCP connection. As you can see, the methods of the Protocol class correspond to an event handling.

When the client connects to the server, the "Connectionmade" method is triggered, in which you can do some authentication, or you can limit the total number of connections to the client. Each instance of protocol has a reference to a factory, and self.factory can be used to access the factory instance where it is located.

The "Cmdprotocol" implemented above is a subclass of Twisted.protocols.basic.LineReceiver, the Linereceiver class separates the data sent by the client into newline characters, triggering the Linereceived method for each line break. Later we can enhance the linereceived to parse the command.

Twisted implements its own log system, where we configure the log output to stdout

When the reactor.listentcp is executed we bind the factory to port 9999 to start listening.

user@lab:~/tmp$ python code1.py2011-08-29 13:32:32+0200 [-] Log opened.2011-08-29 13:32:32+0200 [-] __main__. MyFactory starting on 99992011-08-29 13:32:32+0200 [-] Starting factory <__main__. MyFactory instance at 0x227e3202011-08-29 13:32:35+0200 [__main__. MyFactory] Client connection from 127.0.0.12011-08-29 13:32:38+0200 [cmdprotocol,0,127.0.0.1] CMD received from 127.0.0.1:hello Server

Use twisted to invoke external processes

Next we add a command to the previous server that can read the contents of the/var/log/syslog

Import sysimport osfrom twisted.internet.protocol import serverfactory, Processprotocolfrom Twisted.protocols.basic Import linereceiverfrom Twisted.python import logfrom twisted.internet import Reactorclass tailprotocol ( Processprotocol): Def __init__ (self, write_callback): Self.write = Write_callback def outreceived (self, data): SEL      F.write ("Begin lastlog\n") data = [line for line in Data.split (' \ n ') if not line.startswith (' = = ')] for D in data:      Self.write (d + ' \ n ') self.write ("End lastlog\n") def processended (self, Reason): if reason.value.exitCode! = 0: Log.msg (Reason) class Cmdprotocol (linereceiver): delimiter = ' \ n ' def processcmd (self, line): If Line.startswith ( ' Lastlog '): Tailprotocol = Tailprotocol (self.transport.write) reactor.spawnprocess (Tailprotocol, '/usr/bin/tail '    , args=['/usr/bin/tail ', ' -10 ', '/var/log/syslog ']) elif line.startswith (' exit '): Self.transport.loseConnection () Else:self.transport.write (' Command not 'Found.\n ') def connectionmade (self): Self.client_ip = Self.transport.getPeer () [1] log.msg ("Client connection from% S "% self.client_ip) if Len (self.factory.clients) >= self.factory.clients_max:log.msg (" Too many connections.      Bye! ") Self.client_ip = None self.transport.loseConnection () else:self.factory.clients.append (SELF.CLIENT_IP) def Connectionlost (self, Reason): Log.msg (' Lost client connection. Reason:%s '% Reason) if Self.client_ip:self.factory.clients.remove (SELF.CLIENT_IP) def linereceived (self, line)   : Log.msg (' CMD received from%s:%s '% (self.client_ip, line)) Self.processcmd (line) class MyFactory (serverfactory): protocol = Cmdprotocol def __init__ (self, clients_max=10): Self.clients_max = Clients_max self.clients = []log.st Artlogging (sys.stdout) reactor.listentcp (9999, myfactory (2)) Reactor.run ()

In the above code, do not receive a line from the client after the Processcmd method is executed, if the received line is the Exit command, then the server will be disconnected, if you receive lastlog, we will spit out a child process to execute the tail command, and redirects the output of the tail command to the client. Here we need to implement the Processprotocol class, which needs to override the Processended method and Outreceived method of the class. The Outreceived method is executed when the tail command has output, and the Processended method is executed when the process exits.

Here is an example of the execution result:

user@lab:~/tmp$ python code2.py2011-08-29 15:13:38+0200 [-] Log opened.2011-08-29 15:13:38+0200 [-] __main__. MyFactory starting on 99992011-08-29 15:13:38+0200 [-] Starting factory <__main__. MyFactory instance at 0x1a5a3f8>2011-08-29 15:13:47+0200 [__main__. MyFactory] Client connection from 127.0.0.12011-08-29 15:13:58+0200 [cmdprotocol,0,127.0.0.1] CMD received from 127.0.0.1:test2011-08-29 15:14:02+0200 [cmdprotocol,0,127.0.0.1] Cmd received from 127.0.0.1:lastlog2011-08-29 15:14: 05+0200 [cmdprotocol,0,127.0.0.1] Cmd received from 127.0.0.1:exit2011-08-29 15:14:05+0200 [cmdprotocol,0,127.0.0.1] Lost Client connection. Reason: [Failure instance:traceback (Failure with no frames): 
 
  
   
  : Connection was closed cleanly.
 
  

You can use the following command to initiate a command as a client:

user@lab:~$ netcat 127.0.0.1 9999testCommand found.lastlogbegin Lastlogaug 15:02:03 Lab ssmtp[5919]: Unable to Loca Te Mailaug 15:02:03 Lab ssmtp[5919]: Cannot open Mail:25aug 15:02:03 lab cron[4945]: (CRON) error (Grandchild #4947 Failed with exit status 1) 15:02:03 Lab ssmtp[5922]: Unable to locate Mailaug 15:02:03 Lab ssmtp[5922]: Cannot op En Mail:25aug 15:02:03 Lab cron[4945]: (logcheck) mail (mailed 1 byte of output; but got status 0x0001, #012) 29 15: 05:01 Lab cron[5925]: (Root) CMD (command-v debian-sa1 >/dev/null && DEBIAN-SA1 1 1) 15:10:01 Lab cron[ 5930]: (Root) CMD (test-x/usr/lib/atsar/atsa1 &&/usr/lib/atsar/atsa1) 15:10:01 Lab cron[5928]: (CRON) Err or (grandchild #5930 failed with exit status 1) 15:13:21 Lab pulseaudio[3361]: ratelimit.c:387 Events suppressed En D Lastlogexit

Using the Deferred object

Reactor is a loop in which the loop waits for an event to occur. The events here can be database operations, or long-time computations. As long as these operations can return a deferred object. The deferred object can automatically trigger a callback function when an event occurs. Reactor will block the execution of the current code.

Now we're going to use the Defferred object to calculate the SHA1 hash.

Import sysimport osimport hashlibfrom twisted.internet.protocol import serverfactory, Processprotocolfrom Twisted.protocols.basic Import linereceiverfrom twisted.python import logfrom twisted.internet import reactor, Threadsclass Tailprotocol (processprotocol): Def __init__ (self, write_callback): Self.write = Write_callback def outRe Ceived (self, data): Self.write ("Begin lastlog\n") data = [line for line in Data.split (' \ n ') if not line.startswith (' = = ')] for D in Data:self.write (D + ' \ n ') self.write ("End lastlog\n") def processended (self, Reason): if re Ason.value.exitCode! = 0:log.msg (reason) class Hashcompute (object): Def __init__ (self, Path, write_callback): Sel F.path = Path Self.write = Write_callback def blockingmethod (self): Os.path.isfile (self.path) data = File (self.p   ATH). Read () # Uncomment to add more delay # import time # Time.sleep (Ten) return HASHLIB.SHA1 (data). Hexdigest () def compute (self): D = threads.defertothread (sElf.blockingmethod) D.addcallback (Self.ret) D.adderrback (SELF.ERR) def ret (self, Hdata): Self.write ("File Hash I S:%s\n "% hdata) def err (self, Failure): Self.write (" An error occured:%s\n "% failure.geterrormessage ()) class CMDP Rotocol (linereceiver): delimiter = ' \ n ' def processcmd (self, line): If Line.startswith (' Lastlog '): Tailprotocol = Tailprotocol (self.transport.write) reactor.spawnprocess (Tailprotocol, '/usr/bin/tail ', args=['/usr/bin/tail ', '- '/var/log/syslog ']) elif line.startswith (' Comphash '): try:useless, Path = Line.split (") except      : Self.transport.write (' Please provide a path.\n ') return HC = Hashcompute (path, self.transport.write) Hc.compute () elif line.startswith (' exit '): Self.transport.loseConnection () else:self.transport.write (' Command not found.\n ') def connectionmade (self): Self.client_ip = Self.transport.getPeer () [1] log.msg ("Client con Nection from%s "% SELF.CLIENT_IP) If Len (self.factory.clients) >= self.factory.clients_max:log.msg ("Too many connections.      Bye! ") Self.client_ip = None self.transport.loseConnection () else:self.factory.clients.append (SELF.CLIENT_IP) def Connectionlost (self, Reason): Log.msg (' Lost client connection. Reason:%s '% Reason) if Self.client_ip:self.factory.clients.remove (SELF.CLIENT_IP) def linereceived (self, line)   : Log.msg (' CMD received from%s:%s '% (self.client_ip, line)) Self.processcmd (line) class MyFactory (serverfactory): protocol = Cmdprotocol def __init__ (self, clients_max=10): Self.clients_max = Clients_max self.clients = []log.st Artlogging (sys.stdout) reactor.listentcp (9999, myfactory (2)) Reactor.run ()

Blockingmethod reads a file from the filesystem SHA1, where we use Twisted's Defertothread method, which returns a deferred object. The deferred object here is returned immediately after the call so that the main process can continue to handle other events. The callback function is immediately triggered when the method passed to Defertothread is executed. If there is an error in execution, the Blockingmethod method throws an exception. If successful execution returns the result of the calculation through the hdata ret.
Recommended twisted reading materials

Http://twistedmatrix.com/documents/current/core/howto/defer.html http://twistedmatrix.com/documents/current/ Core/howto/process.html http://twistedmatrix.com/documents/current/core/howto/servers.html

API Documentation:

Http://twistedmatrix.com/documents/current/api/twisted.html

  • Related Article

    Contact Us

    The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

    If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

    A Free Trial That Lets You Build Big!

    Start building with 50+ products and up to 12 months usage for Elastic Compute Service

    • Sales Support

      1 on 1 presale consultation

    • After-Sales Support

      24/7 Technical Support 6 Free Tickets per Quarter Faster Response

    • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.