@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又是派生自BaseProtocol的,继续看这个类的源代码:
@_oldStyle class 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()
可以看到,我们自定义的Spread不过是实现了基类的函数。接下来我们滚一边实现逻辑:
首先,我们定义一个列表clients,以便存储多个客户端的连接。当服务器端接收到了客户端的连接后,调用connectionMade函数,同时,我们给使用Transport客户端发送消息, 通知客户端我们已收到连接。当客户端连接失去的时候,我们调用ConnectionLost, 同时移除列表中的客户端连接, dataReceived函数来接受数据,当客户端传来"close"命令时,我们就主动关闭连接, 否则,我们就把data输出来。
看看客户端的代码:
# coding=utf-8 from twisted.internet.protocol import Protocol, ClientFactory from twisted.internet import reactor import threading import time import sys import datetime class 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: ", reason bStop = False def 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 = 8007 factory = EchoClientFactory() reactor.connectTCP(host, port, factory) threading.Thread(target=routine, args=(factory,)).start() reactor.run() bStop = True