Python network framework basic learning and detailed explanation, pythontwisted

Source: Internet
Author: User

Python network framework basic learning and detailed explanation, pythontwisted

Three basic modules of the twisted network framework: Protocol, ProtocolFactory, and Transport. These three modules constitute the basic of the twisted server and client program.

Protocol: The Protocol content of the Protocol object, that is, the communication content Protocol.
ProtocolFactory: This is the embodiment of the factory model, where the protocol is generated.
Transport: it is used to send and receive data. The data sending and receiving and processing on the server and client are based on this module.

To install twisted in windows, you must first install pywin32 and download it. Then pip install twisted will help us install twisted and zope.

We use a diagram and a program to understand the basic implementation of twisted:

Then let's first look at the server-side program:

# Coding = utf-8from twisted. internet. protocol import Protocolfrom twisted. internet. protocol import Factoryfrom twisted. internet. endpoints import TCP4ServerEndpointfrom twisted. internet import reactorclients = [] class Spreader (Protocol): def _ init _ (self, factory): self. factory = factory def connectionMade (self): self. factory. numProtocols = self. factory. numProtocols + 1 self. transport. write ("Welcome to Sp Read Site. You are the % s client user! \ N "% (self. factory. numProtocols) print "new connect: % d" % (self. factory. numProtocols) clients. append (self) def connectionLost (self, reason): self. factory. numProtocols = self. factory. numProtocols-1 clients. remove (self) print "lost connect: % d" % (self. factory. numProtocols) def dataReceived (self, data): if data = "close": self. transport. loseConnection () for client in clients: if client! = Self: client. transport. write (data) else: print dataclass SpreadFactory (Factory): def _ init _ (self): self. numProtocols = 0 def buildProtocol (self, addr): return Spreader (self) endpoint = TCP4ServerEndpoint (reactor, 8007) endpoint. listen (SpreadFactory () reactor. run ()

Create an IPv4 end point for TCP, and then listen to listen. Here we pass in the Protocol factory object as the parameter. Let's take a look at our custom factory class SpreadFactory, it is derived from the Factory. Let's look at the source code of this class (you need a dictionary at this time :)):

@implementer(interfaces.IProtocolFactory, interfaces.ILoggingContext)@_oldStyleclass Factory:    """    This is a factory which produces protocols.    By default, buildProtocol will create a protocol of the class given in    self.protocol.    """    # put a subclass of Protocol here:    protocol = None    numPorts = 0    noisy = True    @classmethod    def forProtocol(cls, protocol, *args, **kwargs):        """        Create a factory for the given protocol.        It sets the C{protocol} attribute and returns the constructed factory        instance.        @param protocol: A L{Protocol} subclass        @param args: Positional arguments for the factory.        @param kwargs: Keyword arguments for the factory.        @return: A L{Factory} instance wired up to C{protocol}.        """        factory = cls(*args, **kwargs)        factory.protocol = protocol        return factory    def logPrefix(self):        """        Describe this factory for log messages.        """        return self.__class__.__name__    def doStart(self):        """Make sure startFactory is called.        Users should not call this function themselves!        """        if not self.numPorts:            if self.noisy:                _loggerFor(self).info("Starting factory {factory!r}",                                      factory=self)            self.startFactory()        self.numPorts = self.numPorts + 1    def doStop(self):        """Make sure stopFactory is called.        Users should not call this function themselves!        """        if self.numPorts == 0:            # this shouldn't happen, but does sometimes and this is better            # than blowing up in assert as we did previously.            return        self.numPorts = self.numPorts - 1        if not self.numPorts:            if self.noisy:                _loggerFor(self).info("Stopping factory {factory!r}",                                      factory=self)            self.stopFactory()    def startFactory(self):        """This will be called before I begin listening on a Port or Connector.        It will only be called once, even if the factory is connected        to multiple ports.        This can be used to perform 'unserialization' tasks that        are best put off until things are actually running, such        as connecting to a database, opening files, etcetera.        """    def stopFactory(self):        """This will be called before I stop listening on all Ports/Connectors.        This can be overridden to perform 'shutdown' tasks such as disconnecting        database connections, closing files, etc.        It will be called, for example, before an application shuts down,        if it was connected to a port. User code should not call this function        directly.        """    def buildProtocol(self, addr):        """        Create an instance of a subclass of Protocol.        The returned instance will handle input on an incoming server        connection, and an attribute "factory" pointing to the creating        factory.        Alternatively, L{None} may be returned to immediately close the        new connection.        Override this method to alter how Protocol instances get created.        @param addr: an object implementing L{twisted.internet.interfaces.IAddress}        """        p = self.protocol()        p.factory = self        return p

A very important function here is buildProtocol, which creates a protocol in the factory mode. we implement this function based on the base class Factory. Let's take a look at the Protocol Class Spread derived from Protocol and the _ Init _ parameter of Spread, we pass in a custom SpreadFactory for it, and then we can look at the source code of the base class Protocol.

@implementer(interfaces.IProtocol, interfaces.ILoggingContext)class Protocol(BaseProtocol):    """    This is the base class for streaming connection-oriented protocols.    If you are going to write a new connection-oriented protocol for Twisted,    start here.  Any protocol implementation, either client or server, should    be a subclass of this class.    The API is quite simple.  Implement L{dataReceived} to handle both    event-based and synchronous input; output can be sent through the    'transport' attribute, which is to be an instance that implements    L{twisted.internet.interfaces.ITransport}.  Override C{connectionLost} to be    notified when the connection ends.    Some subclasses exist already to help you write common types of protocols:    see the L{twisted.protocols.basic} module for a few of them.    """    def logPrefix(self):        """        Return a prefix matching the class name, to identify log messages        related to this protocol instance.        """        return self.__class__.__name__    def dataReceived(self, data):        """Called whenever data is received.        Use this method to translate to a higher-level message.  Usually, some        callback will be made upon the receipt of each complete protocol        message.        @param data: a string of indeterminate length.  Please keep in mind            that you will probably need to buffer some data, as partial            (or multiple) protocol messages may be received!  I recommend            that unit tests for protocols call through to this method with            differing chunk sizes, down to one byte at a time.        """    def connectionLost(self, reason=connectionDone):        """Called when the connection is shut down.        Clear any circular references here, and any external references        to this Protocol.  The connection has been closed.        @type reason: L{twisted.python.failure.Failure}        """

Protocol is derived from BaseProtocol. Continue to read the source code of this class:

@_oldStyleclass BaseProtocol:    """    This is the abstract superclass of all protocols.    Some methods have helpful default implementations here so that they can    easily be shared, but otherwise the direct subclasses of this class are more    interesting, L{Protocol} and L{ProcessProtocol}.    """    connected = 0    transport = None    def makeConnection(self, transport):        """Make a connection to a transport and a server.        This sets the 'transport' attribute of this Protocol, and calls the        connectionMade() callback.        """        self.connected = 1        self.transport = transport        self.connectionMade()    def connectionMade(self):        """Called when a connection is made.        This may be considered the initializer of the protocol, because        it is called when the connection is completed.  For clients,        this is called once the connection to the server has been        established; for servers, this is called after an accept() call        stops blocking and a socket has been received.  If you need to        send any greeting or initial message, do it here.        """connectionDone=failure.Failure(error.ConnectionDone())connectionDone.cleanFailure()

We can see that the custom Spread only implements the base class function. Next we will implement the logic by rolling one side:
First, we define a list of clients to store connections from multiple clients. When the server receives a connection from the client, it calls the connectionMade function and sends a message to the Transport client to notify the client that the connection has been received. When the client connection is lost, we call ConnectionLost and remove the client connection from the list. The dataReceived function accepts the data. When the client sends the "close" command, we close the connection, otherwise, we will output data.

Check the client code:

# coding=utf-8from twisted.internet.protocol import Protocol, ClientFactoryfrom twisted.internet import reactorimport threadingimport timeimport sysimport datetimeclass Echo(Protocol):    def __init__(self):        self.connected = False    def connectionMade(self):        self.connected = True    def connectionLost(self, reason):        self.connected = False    def dataReceived(self, data):        print data.decode("utf-8")class EchoClientFactory(ClientFactory):    def __init__(self):        self.protocol = None    def startedConnecting(self, connector):        print "Start to Connect..."    def buildProtocol(self, addr):        print "Connected..."        self.protocol = Echo()        return self.protocol    def clientConnectionLost(self, connector, reason):        print "Lost connection. Reason: ", reason    def clientConnectionFailed(self, connector, reason):        print "Connection is failed, Reason: ", reasonbStop = Falsedef routine(factory):    while not bStop:        if factory.protocol and factory.protocol.connected:            factory.protocol.transport.write("hello, I'm %s %s" % (                sys.argv[0], datetime.datetime.now()            ))            print sys.argv[0], datetime.datetime.now()        time.sleep(5)host = '127.0.0.1'port = 8007factory = EchoClientFactory()reactor.connectTCP(host, port, factory)threading.Thread(target=routine, args=(factory,)).start()reactor.run()bStop = True

At first, we established a TCP connection, passed in the host address, port, and Protocol factory object as the parameter, and then reactor. run suspended.
Next let's take a look at the ClientFactory base class, because our custom protocol factory EchoClientFactory is derived from it. Source code:

class ClientFactory(Factory):    """A Protocol factory for clients.    This can be used together with the various connectXXX methods in    reactors.    """    def startedConnecting(self, connector):        """Called when a connection has been started.        You can call connector.stopConnecting() to stop the connection attempt.        @param connector: a Connector object.        """    def clientConnectionFailed(self, connector, reason):        """Called when a connection has failed to connect.        It may be useful to call connector.connect() - this will reconnect.        @type reason: L{twisted.python.failure.Failure}        """    def clientConnectionLost(self, connector, reason):        """Called when an established connection is lost.        It may be useful to call connector.connect() - this will reconnect.        @type reason: L{twisted.python.failure.Failure}        """

Similarly, our custom EchoClientFactory is just a function that is not implemented in the base class. The most important one is buildProtocol, which generates a protocol for us, next let's take a look at our custom protocol class Echo. the source code of the base class is the same as the above.
The protocol functions of the client are the same as those of the server.

The twisted module of the client is finished, and then we create a thread to communicate with the server and send it regularly. Of course, in this case, you must determine whether a connection has been established with the server before sending a message.

I 've probably talked about the basic part. All the code is from the code in "efficient python development practice". I also recommend this book to you here. There are two good tutorials to learn about twisted, at the end of the day, I will share Baidu online storage. The reason for writing this article is to be able to understand the last project in the efficient development practice: using Twisted to develop a cross-platform Iot message gateway. Because I first got into contact with Iot communication, I rolled the source code of the project (written in java, but I also learned C # after all #,. net for two years, there is no pressure to understand the project source code, mvc orm is consistent. in net, EF and MVC are similar, but the syntax is a little different.) It is similar to the project in the book. The communication protocol commands of the server and client are clearly described in the book. Therefore, this is a good book that cannot be missed. It is also the best way to learn and master twisted.

Finally, run the test:

Server:

Client:

Twisted Tutorial: http://pan.baidu.com/s/1dEBPGhN

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.