python 网络框架twisted基础学习及详细讲解
twisted網(wǎng)絡(luò)框架的三個(gè)基礎(chǔ)模塊:Protocol, ProtocolFactory, Transport.這三個(gè)模塊是構(gòu)成twisted服務(wù)器端與客戶端程序的基本。
Protocol:Protocol對象實(shí)現(xiàn)協(xié)議內(nèi)容,即通信的內(nèi)容協(xié)議
ProtocolFactory: 是工廠模式的體現(xiàn),在這里面生成協(xié)議
Transport: 是用來收發(fā)數(shù)據(jù),服務(wù)器端與客戶端的數(shù)據(jù)收發(fā)與處理都是基于這個(gè)模塊
在windows中安裝twisted需要先安裝pywin32,自己去下載下就行。隨后pip install twisted就會(huì)幫我們安裝twisted以及zope。
我們結(jié)合一張圖,以及一段程序來理解下twisted的基礎(chǔ)實(shí)現(xiàn):
然后我們首先看看服務(wù)器端程序:
創(chuàng)建一個(gè)TCP的IPv4版本的終結(jié)點(diǎn),隨后就開始監(jiān)聽listen, 在這里我們傳入?yún)f(xié)議工廠對象作為參數(shù), 先看看我們自定義的工廠類SpreadFactory, 它派生自Factory, 我們看看這個(gè)類的源碼(此時(shí)你需要有道詞典了:) ):
@implementer(interfaces.IProtocolFactory, interfaces.ILoggingContext) @_oldStyle class Factory:"""This is a factory which produces protocols.By default, buildProtocol will create a protocol of the class given inself.protocol."""# put a subclass of Protocol here:protocol = NonenumPorts = 0noisy = True@classmethoddef forProtocol(cls, protocol, *args, **kwargs):"""Create a factory for the given protocol.It sets the C{protocol} attribute and returns the constructed factoryinstance.@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 = protocolreturn factorydef 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 + 1def 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.returnself.numPorts = self.numPorts - 1if 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 connectedto multiple ports.This can be used to perform 'unserialization' tasks thatare best put off until things are actually running, suchas 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 disconnectingdatabase 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 functiondirectly."""def buildProtocol(self, addr):"""Create an instance of a subclass of Protocol.The returned instance will handle input on an incoming serverconnection, and an attribute "factory" pointing to the creatingfactory.Alternatively, L{None} may be returned to immediately close thenew 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 = selfreturn p在這里很重要的一個(gè)函數(shù)就是buildProtocol, 此函數(shù)就是在工廠模式中創(chuàng)建協(xié)議的.我們是基于基類Factory來實(shí)現(xiàn)這個(gè)函數(shù)的, 下面我們看看派生自Protocol的協(xié)議類Spread,Spread的__Init__參數(shù)中,我們給它傳入的是自定義的SpreadFactory, 然后我們看下基類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, shouldbe a subclass of this class.The API is quite simple. Implement L{dataReceived} to handle bothevent-based and synchronous input; output can be sent through the'transport' attribute, which is to be an instance that implementsL{twisted.internet.interfaces.ITransport}. Override C{connectionLost} to benotified 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 messagesrelated 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, somecallback will be made upon the receipt of each complete protocolmessage.@param data: a string of indeterminate length. Please keep in mindthat you will probably need to buffer some data, as partial(or multiple) protocol messages may be received! I recommendthat unit tests for protocols call through to this method withdiffering 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 referencesto this Protocol. The connection has been closed.@type reason: L{twisted.python.failure.Failure}"""而Protocol又是派生自BaseProtocol的,繼續(xù)看這個(gè)類的源代碼:
@_oldStyle class BaseProtocol:"""This is the abstract superclass of all protocols.Some methods have helpful default implementations here so that they caneasily be shared, but otherwise the direct subclasses of this class are moreinteresting, L{Protocol} and L{ProcessProtocol}."""connected = 0transport = Nonedef makeConnection(self, transport):"""Make a connection to a transport and a server.This sets the 'transport' attribute of this Protocol, and calls theconnectionMade() callback."""self.connected = 1self.transport = transportself.connectionMade()def connectionMade(self):"""Called when a connection is made.This may be considered the initializer of the protocol, becauseit is called when the connection is completed. For clients,this is called once the connection to the server has beenestablished; for servers, this is called after an accept() callstops blocking and a socket has been received. If you need tosend any greeting or initial message, do it here."""connectionDone=failure.Failure(error.ConnectionDone()) connectionDone.cleanFailure()可以看到,我們自定義的Spread不過是實(shí)現(xiàn)了基類的函數(shù)。接下來我們滾一邊實(shí)現(xiàn)邏輯:
首先,我們定義一個(gè)列表clients,以便存儲(chǔ)多個(gè)客戶端的連接。當(dāng)服務(wù)器端接收到了客戶端的連接后,調(diào)用connectionMade函數(shù),同時(shí),我們給使用Transport客戶端發(fā)送消息, 通知客戶端我們已收到連接。當(dāng)客戶端連接失去的時(shí)候,我們調(diào)用ConnectionLost, 同時(shí)移除列表中的客戶端連接, dataReceived函數(shù)來接受數(shù)據(jù),當(dāng)客戶端傳來"close"命令時(shí),我們就主動(dòng)關(guān)閉連接, 否則,我們就把data輸出來。
看看客戶端的代碼:
一開始我們建立TCP連接, 傳入主機(jī)地址, 端口, 協(xié)議工廠對象作為參數(shù),隨后reactor.run掛起運(yùn)行。
下面我們看看ClientFactory基類,因?yàn)槲覀冏远x的協(xié)議工廠EchoClientFactory派生自它。源碼:
同樣的,我們自定義的EchoClientFactory不過就是實(shí)現(xiàn)了基類中沒有實(shí)現(xiàn)的函數(shù),其中最重要的還是buildProtocol, 它為我們生成一個(gè)協(xié)議,下面看下我們自定義的協(xié)議類Echo, 基類源代碼與上面的是一樣的.
客戶端的協(xié)議函數(shù)與服務(wù)器端的協(xié)議函數(shù)是一樣的,在這里就不多說。
客戶端的twisted模塊講完了,隨后我們創(chuàng)建了一個(gè)線程去和服務(wù)器端通信, 并且定時(shí)發(fā)送, 當(dāng)然,在這里我們?yōu)榱艘苑廊f一,需要判斷是否已經(jīng)與服務(wù)器取得了連接,隨后才發(fā)送消息.
大概講了下基礎(chǔ)部分,所有的代碼都是來自《python高效開發(fā)實(shí)戰(zhàn)》里的代碼,在這里也向大家推薦這本書,學(xué)習(xí)twisted還有兩個(gè)不錯(cuò)的教程,在最后我會(huì)發(fā)百度網(wǎng)盤共享。之所以寫這篇基礎(chǔ)的,就是為了能夠理解高效開發(fā)實(shí)戰(zhàn)里的最后一個(gè)項(xiàng)目: 用Twisted開發(fā)跨平臺(tái)物聯(lián)網(wǎng)消息網(wǎng)關(guān)。因?yàn)榈谝淮螌?shí)習(xí)就接觸到了物聯(lián)網(wǎng)通信,在工作時(shí),滾了一遍項(xiàng)目的源代碼(java寫的,但我畢竟也是學(xué)了C#, .net兩年的人, 看懂項(xiàng)目源碼沒壓力, mvc orm都是與.net中的EF, MVC差不多, 不過就是語法有點(diǎn)不同),正好和書上的這個(gè)項(xiàng)目差不多,書上將服務(wù)器與客戶端的通信協(xié)議指令都講得很清楚。因此這是一本不容錯(cuò)過的好書, 也是學(xué)習(xí), 精通twisted的最好途徑
最后就是運(yùn)行測試:
服務(wù)器端:
客戶端:
?
總結(jié)
以上是生活随笔為你收集整理的python 网络框架twisted基础学习及详细讲解的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: httrack 拷贝网站到本地(好东西,
- 下一篇: Linux系统运行Windows程序(L