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