Introduction to the Twisted framework under Python _python

Source: Internet
Author: User
Tags sha1 sha1 hash syslog ssh server in python

What is twisted?

Twisted is an event-driven network framework written in Python, and he supports a variety of protocols, including UDP,TCP,TLS and other application layer protocols, such as Http,smtp,nntm,irc,xmpp/jabber. A very good point is that twisted implementations and many application-level protocols, developers can simply use these protocols for 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 connects to the server, the server-side events are triggered to execute.
write a simple TCP server with twisted

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

= = = = Code1.py = = = Import sys from twisted.internet.protocol import serverfactory from twisted.protocols.basic import Lin Ereceiver from Twisted.python import log from twisted.internet Import reactor class Cmdprotocol (Linereceiver): Delimit er = ' \ n ' def connectionmade (self): Self.client_ip = Self.transport.getPeer () [1] log.msg ("Client connection fro M%s "% self.client_ip" if Len (self.factory.clients) >= self.factory.clients_max:log.msg ("Too many Connectio Ns.
      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, l INE): Log.msg (' CMD received from%s:%s '% (self.client_ip, line)) class MyFactory (serverfactory): protocol = cmd Protocol def __init__ (self, clients_max=10): Self. Clients_max = Clients_max self.clients = [] log.startlogging (sys.stdout) reactor.listentcp (9999, MyFactory (2)) react

 Or.run ()

The following code is critical:

From twisted.internet Import reactor
Reactor.run ()

These two lines of code start the Reator main loop.

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

When the client is connected to the server, the "Connectionmade" method is triggered, in which you can do some authentication, or limit the total number of connections to the client. Each instance of protocol has a reference to a factory that uses Self.factory to access the factory instance in which it is located.

The "Cmdprotocol" that is implemented above is a subclass of Twisted.protocols.basic.LineReceiver, the Linereceiver class separates the data sent by the client by a newline character, and every newline character triggers the linereceived method. Later we can enhance the linereceived to resolve the command.

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

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

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

Using twisted to invoke an external process

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

Import sys import OS from twisted.internet.protocol import serverfactory, processprotocol from Twisted.protocols.basic i Mport linereceiver from Twisted.python import log from twisted.internet Import reactor class Tailprotocol (Processprotocol ): Def __init__ (self, write_callback): Self.write = Write_callback def outreceived (self, data): Self.write ("B Egin 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.starts With (' Lastlog '): Tailprotocol = Tailprotocol (self.transport.write) reactor.spawnprocess (Tailprotocol, '/usr/bi N/tail ', args=['/usr/bin/tail ', ' -10 ', '/var/log/syslog '] elif line.startswith (' exit '): Self.transport.loseConn
     Ection () 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_ma X: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, l INE): Log.msg (' CMD received from%s:%s '% (self.client_ip, line)] Self.processcmd (line) class MyFactory (ServerF Actory): protocol = Cmdprotocol def __init__ (self, clients_max=10): Self.clients_max = Clients_max Self.clie

 NTS = [] log.startlogging (sys.stdout) reactor.listentcp (9999, myfactory (2)) Reactor.run ()

In the code above, the Processcmd method is executed without receiving a line of content from the client, and if the line received is the Exit command, the server end is disconnected and, if the Lastlog is received, we spit out a subprocess 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 requires rewriting 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.

The following are examples of execution results:

user@lab:~/tmp$ python code2.py
2011-08-29 15:13:38+0200 [-] Log opened.
2011-08-29 15:13:38+0200 [-] __main__. MyFactory starting on 9999
2011-08-29 15:13:38+0200 [-] starting factory. MyFactory instance at 0x1a5a3f8>
2011-08-29 15:13:47+0200 [__main__. MyFactory] Client connection from 127.0.0.1
2011-08-29 15:13:58+0200 [cmdprotocol,0,127.0.0.1] CMD received from 127.0.0.1:test
2011-08-29 15:14:02+0200 [cmdprotocol,0,127.0.0.1] Cmd received from 127.0.0.1:lastlog
2011-08-29 15:14:05+0200 [cmdprotocol,0,127.0.0.1] Cmd received from 127.0.0.1:exit
2011-08-29 15:14:05+0200 [ cmdprotocol,0,127.0.0.1] Lost Client connection. Reason: [Failure Instance:traceback (failure with no frames): <class ' Twisted.internet.error.ConnectionDone ': Connection was closed cleanly.

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

user@lab:~$ netcat 127.0.0.1 9999
test
Command not found.
Lastlog
Begin lastlog
Aug 15:02:03 Lab ssmtp[5919]: Unable to locate mail
Aug Lab 15:02:03]: Cannot open mail:25
Aug 15:02:03 Lab cron[4945]: (CRON) error (grandchild #4947 failed with exit status 1)
Aug 15:02:03 Lab ssmtp[5922]: Unable to locate mail
Aug 15:02:03 Lab ssmtp[5922]: Cannot open mail:25
Aug 29 15 : 02:03 Lab cron[4945]: (logcheck) MAIL (mailed 1 byte of output; but got status 0x0001, #012)
Aug 15:05:01 Lab CRO N[5925]: (Root) CMD (command-v debian-sa1 >/dev/null && DEBIAN-SA1 1 1)
Aug-15:10:01 Lab cron[5930]: (Root) CMD (test-x/usr/lib/atsar/atsa1 &&/usr/lib/atsar/atsa1)
Aug 15:10:01 Lab cron[5928]: (CRON) Error (Gran Dchild #5930 failed with exit status 1
Aug 15:13:21 Lab pulseaudio[3361]: ratelimit.c:387 events suppressed
   
    end Lastlog
Exit


   

Using the Deferred object

Reactor is a loop in which the loop waits for the event to occur. The event here can be a database operation, or it can be a long-running calculation operation. 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 compute the SHA1 hash.

Import SYS import OS import hashlib from Twisted.internet.protocol import serverfactory, processprotocol from TWISTED.PR Otocols.basic Import linereceiver from Twisted.python import log from twisted.internet import reactor, threads class Tail Protocol (processprotocol): Def __init__ (self, write_callback): Self.write = Write_callback def outreceived (self, Data): Self.write ("Begin lastlog\n") data = [line for line in Data.split (' \ n ') if not line.startswith (' = = ')] F or 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 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 (s Elf.path). Read () # uncomment to add delay # import Time # Time.sleep (a) return HASHLIB.SHA1 (data). He Xdigest () def COMPUTE(self): D = Threads.defertothread (Self.blockingmethod) d.addcallback (Self.ret) D.adderrback (SELF.ERR) def R  ET (self, hdata): Self.write ("File hash is:%s\n"% hdata) def err (self, Failure): Self.write ("An error occured 
    :%s\n "% failure.geterrormessage ()) class Cmdprotocol (linereceiver): delimiter = ' \ n ' def processcmd (self, line): If Line.startswith (' Lastlog '): Tailprotocol = Tailprotocol (self.transport.write) reactor.spawnprocess (Tai
      Lprotocol, '/usr/bin/tail ', args=['/usr/bin/tail ', ' -10 ', '/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 '): SEL
    F.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) >= sel F.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, l INE): Log.msg (' CMD received from%s:%s '% (self.client_ip, line)] Self.processcmd (line) class MyFactory (ServerF Actory): protocol = Cmdprotocol def __init__ (self, clients_max=10): Self.clients_max = Clients_max Self.clie

 NTS = [] log.startlogging (sys.stdout) reactor.listentcp (9999, myfactory (2)) Reactor.run ()

Blockingmethod reads a file from the file system to compute SHA1, where we use the twisted Defertothread method, which returns a deferred object. The deferred object here is returned immediately after the call, so the main process can continue to handle other events. The callback function is immediately triggered when the method passed to Defertothread is completed. If there is an error in execution, the Blockingmethod method throws an exception. If successful execution returns the result of the calculation through a 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.