Implement a simple server using Python's Twisted framework

  • 2020-05-09 18:51:41
  • OfStack

preview
  twisted is a very flexible framework designed to allow you to write very powerful servers. Is the price of this kind of flexible need good to achieve your server through several levels, Protocol layer is described in this document, you will be at this level of implementation of protocol analysis and processing, if you are performing a application, then you should be reading top level writing a plug-in for twisted 1 section of how to start writing twisted application after reading this chapter. This document is only about TCP, SSL and Unix socket servers, and there will be another document devoted to UDP.
  your protocol handler class is usually twisted. internet. protocol. Protocol subclass. Many protocols deal with subclasses of a class that inherit from or are more convenient than that class. An instance of the protocol class may connect repeatedly or be destroyed after the connection is closed. This means that this constant configuration information is not stored in Protocol.
    these persistent configuration is stored in the factory (Factory) class, usually these factory class inheritance to twisted. internet. protocol. Factory, default factory class is instantiated only each Protocol, and then set their factory attribute to the default factory instance itself. This allows each Protocol to be stored and possibly modified, thus resulting in the persistence of Protocol.
    is often useful for providing the same service for multiple ports or network addresses. That's why Factory doesn't listen for connections, and it doesn't actually know anything about the network. See twisted. internet. interfaces. IReactorTCP. listenTCP, another 1 IReactor *. listen * get more information.


This document explains the steps.


Protocol
As mentioned above,       is explained here through more code's helper classes and functions. One twisted protocl processes data asynchronously. This means that protocol never waits for anything. Instead, respond to events as they arrive over the network.


from twisted.internet.protocol import Protocol
class Echo(Protocol):
 def dataReceived(self,data):
  self.transport.writed(data)

This is a very simple protocol that simply sends the received data back in the event of getting the data, and does not respond to all the events. Here is an example of Protocol responding to other events:


from twisted.internet.protocol import Protocol
class QOTD(Protocol):
 def connectionMade(self):
  self.transport.write("An apple a day keeps the doctor away/r/n") 
  self.transport.loseConnection()

      this Protocl in a known reference when connected to respond at first, sent a message, and then terminated the connection connectionMade events is often triggered when due to the initial connection object connected, like the above QOTD class is actually RFC865 document no. 1 protocol base class connectionLost event will be triggered when disconnected. Example:    
             


<span style="font-family: Monospaced; color: #0000a0;"><strong>PythonCode: </strong></span><table style="width: 100%; height: 20px;" align="center" bgcolor="#e3dfe3" border="1" bordercolor="#9da7ac" cellpadding="0" cellspacing="0"> 
  <tbody><tr><td> 
     <div class="textBackGround" style="font-family:Courier New;font-size:9pt;"><pre><span style="color: blue;">from</span> twisted.internet.protocol <span style="color: blue;">import</span> Protocol 
 <span style="color: blue;">class</span> Echo(Protocol): 
  <span style="color: blue;">def</span> connectionMade(self): 
   self.factory.numProtocols = self.factory.numProtocols+1 
   <span style="color: blue;">if</span> self.factory.numProtocols > 100: 
    self.transport.write(<span style="color: #ff44a2;">"Too many connections, <span style="color: blue;">try</span> later"</span>) 
    self.transport.loseConnection() 
  <span style="color: blue;">def</span> connectionLost(self, reason): 
   self.factory.numProtocols = self.factory.numProtocols-1 
  <span style="color: blue;">def</span> dataReceived(self, data): 
   self.transport.write(data)</pre> 
 </div> 
 </td> 
 </tr> 
 </tbody> 
 </table> 

In this example, connectionMade and connectionLost work together to keep the number of active connections within factory to a maximum of 100. Whenever a user protocol connection is recent, the number of active connections inside factory is first detected. If the number exceeds 100, too many connections will be sent and a message will be tried. Then the connection will be disconnected, while connectionLost will be triggered when one protocol is disconnected, minus the number of active connections inside factory.

Using the Protocol

In this section, I'm going to show you how to easily test your protocol. Want to know how to write a good twisted server < a href="http://fantix.org/twisted-doc-zh/nightly/online/howto/plugin.html" > Writing Plug-Ins < br >       for Twisted < /a > ), here is a code that will run the QOTD server we talked about above:    
     


 <!-- 
 .textBackGround {background-color: #F0F5FD;} 
 --> 
  <span style="font-family: Monospaced; color: #0000a0;"><strong>PythonCode: </strong></span><table style="width: 100%; height: 20px;" align="center" bgcolor="#e3dfe3" border="1" bordercolor="#9da7ac" cellpadding="0" cellspacing="0"> 
  <tbody><tr><td> 
     <div class="textBackGround" style="font-family:Courier New;font-size:9pt;"><pre><span style="color: blue;">from</span> twisted.internet.protocol <span style="color: blue;">import</span> Protocol, Factory 
 <span style="color: blue;">from</span> twisted.internet <span style="color: blue;">import</span> reactor 
 <span style="color: blue;">class</span> QOTD(Protocol): 
  <span style="color: blue;">def</span> connectionMade(self): 
   self.transport.write(<span style="color: #ff44a2;">"An apple a day keeps the doctor away/r/n"</span>) 
   self.transport.loseConnection() 
  
 <span style="color: green;"># Next lines are magic:</span> 
 factory = Factory() 
 factory.protocol = QOTD 
  
 <span style="color: green;"># 8007 <span style="color: blue;">is</span> the port you want to run under. Choose something >1024</span> 
 reactor.listenTCP(8007, factory) 
 reactor.run()</pre> 
 </div> 
 </td> 
 </tr> 
 </tbody> 
 </table> 

      don't have to worry about the last six pieces of code, you'll learn about them later in this document. < br >  

Helper Protocols

        most protocols relies on lower level super classes of the same class. The most popular Internet protocol is based on lines, which are usually made up of CR_LF(enter line feed)
However, there are quite a few protocols that are mixed, with both linear base nodes and raw data nodes, such as HTTP/1.1.
        in this case, we can use LineReceiver, this protocol class has two different event handling methods, lineReceived and rawDataReceived
By default, only lineReceived is called, reading 1 row at a time, whereas if setRawMode is called, protocol will call rawDataReceived
Until setLineMode is called. Here is a simple example of how to use lineReceiver:

      PythonCode:                          


from twisted.protocols.basic import LineReceiver
class Answer(LineReceiver):
 answers = {'How are you?': 'Fine', None : "I don't know what you mean"}
 def lineReceived(self, line):
  if self.answers.has_key(line):
   self.sendLine(self.answers[line])
  else:
   self.sendLine(self.answers[None])

Note: the delimiter is not part 1 of the command line
Other unpopular protocols still exist, such as netstring based and a prefixed-message-length

State Machines

        many twisted protocol handlers need to write a state machine to record their current state. Here are some Suggestions for writing a state machine:
1. Don't write a big state machine, but rather implement an abstract state machine class
    2. Use the dynamic nature of python to create unbounded state machines, such as SMTP clients
    3. Do not mix application-specific code with protocol handling code. When the protocol handler has made a specific request, keep it as a method call.

Factories (factory class)

        as said earlier, usually twisted. internet. protocol. Factory without subclassing can begin to work. Sometimes, however, protocol needs to be specific
Special factory configuration information or other requirements, in which case subclassing is required.
For Factory,       simply instantiates a special protocol protocol class, instantiates Factory, and sets protocol properties:

      PythonCode:                          


from twisted.internet.protocol import Factory
from twisted.protocols.wire import Echo

myFactory = Factory()
myFactory.protocol = Echo

An factory function is useful if you simply need to construct a factory class with specific information:

PythonCode:


class QOTD(Protocol):
 def connectionMade(self):
  self.transport.write(self.factory.quote+'/r/n')
  self.transport.loseConnection()

def makeQOTDFactory(quote=None):
 factory = Factory()
 factory.protocol = QOTD
 factory.quote = quote or 'An apple a day keeps the doctor away'
 return factory


One Factory has two methods to perform the application-specific build and dismantle (as one Factory is usually present, general rule 1 will not be allowed either
S 271en __ to allocate and reclaim them, either too early or too late.
Here is an example of Factory, which will allow Protocol to write a log file:      
PythonCode:


from twisted.internet.protocol import Factory
from twisted.protocols.basic import LineReceiver

class LoggingProtocol(LineReceiver):

 def lineReceived(self, line):
  self.factory.fp.write(line+'/n')


class LogfileFactory(Factory):

 protocol = LoggingProtocol

 def __init__(self, fileName):
  self.file = fileName

 def startFactory(self):
  self.fp = open(self.file, 'a')

 def stopFactory(self):
  self.fp.close()

Putting it All Together

      now that you know Factory and want to perform QOTD as a configurable quote server, right? There is no problem here is a code:
      PythonCode:                          


from twisted.internet.protocol import Factory, Protocol
from twisted.internet import reactor

class QOTD(Protocol):

 def connectionMade(self):
  self.transport.write(self.factory.quote+'/r/n')
  self.transport.loseConnection()


class QOTDFactory(Factory):

 protocol = QOTD

 def __init__(self, quote=None):
  self.quote = quote or 'An apple a day keeps the doctor away'

reactor.listenTCP(8007, QOTDFactory("configurable quote"))
reactor.run()

Those are the last two lines of code, and you need to understand them.
listenTCP is a method of connecting Factory to the network. It USES reactor's interface to allow many different loops to process network code without modification
End user code, just like that. As mentioned earlier, if you want to write a good twisted server instead of just 20 lines, then you need to use the Application object.


Related articles: