卷2:第21章 Twisted

2018-02-24 15:55 更新

原文鏈接:http://www.aosabook.org/en/twisted.html

作者:Jessica McKellar

Twisted是用Python實(shí)現(xiàn)的基于事件驅(qū)動的網(wǎng)絡(luò)引擎框架。Twisted誕生于2000年初,在當(dāng)時的網(wǎng)絡(luò)游戲開發(fā)者看來,無論他們使用哪種語言,手中都鮮有可兼顧擴(kuò)展性及跨平臺的網(wǎng)絡(luò)庫。Twisted的作者試圖在當(dāng)時現(xiàn)有的環(huán)境下開發(fā)游戲,這一步走的非常艱難,他們迫切地需要一個可擴(kuò)展性高、基于事件驅(qū)動、跨平臺的網(wǎng)絡(luò)開發(fā)框架,為此他們決定自己實(shí)現(xiàn)一個,并從那些之前的游戲和網(wǎng)絡(luò)應(yīng)用程序的開發(fā)者中學(xué)習(xí),汲取他們的經(jīng)驗(yàn)教訓(xùn)。

Twisted支持許多常見的傳輸及應(yīng)用層協(xié)議,包括TCP、UDP、SSL/TLS、HTTP、IMAP、SSH、IRC以及FTP。就像Python一樣,Twisted也具有“內(nèi)置電池”(batteries-included)的特點(diǎn)。Twisted對于其支持的所有協(xié)議都帶有客戶端和服務(wù)器實(shí)現(xiàn),同時附帶有基于命令行的工具,使得配置和部署產(chǎn)品級的Twisted應(yīng)用變得非常方便。

21.1 為什么需要Twisted

2000年時,Twisted的作者Glyph正在開發(fā)一個名為Twisted Reality的基于文本方式的多人在線游戲。這個游戲采用Java開發(fā),里面盡是一堆線程——每個連接就有3個線程處理。處理輸入的線程會在讀操作上阻塞,處理輸出的線程將在一些寫操作上阻塞,還有一個“邏輯”線程將在等待定時器超時或者事件入隊(duì)列時休眠。隨著玩家們在虛擬世界中移動并交互時,線程出現(xiàn)死鎖,緩存被污染,程序中的加鎖邏輯幾乎從來就沒對過——采用多線程使得整個軟件變得復(fù)雜、漏洞百出而且極難擴(kuò)展。

為了尋求其他的解決方案,作者發(fā)現(xiàn)了Python,特別是Python中用于對流式對象比如socket和pipe進(jìn)行多路I/O復(fù)用的select模塊(UNIX規(guī)范第3版(SUSv3)描述了select)。那時,Java并沒有提供操作系統(tǒng)的select接口或者任何其他的異步I/O API(針對非阻塞式I/O的包java.nio已經(jīng)在J2SE 1.4中加入了,2002年發(fā)布)。通過用Python中的select模塊快速搭建起游戲的原型,這迅速降低了程序的復(fù)雜度,并且比多線程版本要更加可靠。

Glyph迅速轉(zhuǎn)向了Python、select以及基于事件驅(qū)動的編程。他使用Python的select模塊為游戲編寫了客戶端和服務(wù)器。但他想要的還不止于此。從根本上說,他希望能將網(wǎng)絡(luò)行為轉(zhuǎn)變?yōu)閷τ螒蛑械膶ο蟮姆椒ㄕ{(diào)用。如果你能在游戲中收取郵件會怎樣,就像Nethack mailer這種守護(hù)進(jìn)程一樣?如果游戲中的每位玩家都擁有一個主頁呢?Glyph發(fā)現(xiàn)他需要優(yōu)秀的IMAP以及HTTP客戶端和服務(wù)器的Python實(shí)現(xiàn),而這些都要采用select。

他首先轉(zhuǎn)向了Medusa,這是一個在90年代中期開發(fā)的平臺,在這里可以采用Python中的asyncore模塊來編寫網(wǎng)絡(luò)服務(wù)。asyncore是一個異步化處理socket的模塊,在操作系統(tǒng)的select API之上構(gòu)建了一個調(diào)度器和回調(diào)接口。

這對于Glyph來說是個激動人心的發(fā)現(xiàn),但Medusa有兩個缺點(diǎn):

  1. 這個項(xiàng)目到2001年就不再維護(hù)了,那正是glyph開發(fā)Twisted Reality的時候。
  2. asyncore只是對socket的一個薄封裝層,應(yīng)用程序的編寫者仍然需要直接操作socket。這意味著程序可移植性的擔(dān)子仍然落在程序員自己身上。此外,那時asyncore對Windows的支持還有問題,Glyph希望能在Windows上運(yùn)行一個帶有圖形用戶界面的客戶端。

Glyph需要自己實(shí)現(xiàn)一個網(wǎng)絡(luò)引擎平臺,而且他意識到Twisted Reality已經(jīng)打開了問題的大門,這和他的游戲一樣有趣。

隨著時間的推移,Twisted Reality這個游戲就演化成了Twisted網(wǎng)絡(luò)引擎平臺。它可以做到當(dāng)時Python中已有的網(wǎng)絡(luò)平臺所無法做到的事情:

  • 使用基于事件驅(qū)動的編程模型,而不是多線程模型。
  • 跨平臺:為主流操作系統(tǒng)平臺暴露出的事件通知系統(tǒng)提供統(tǒng)一的接口。
  • “內(nèi)置電池”的能力:提供流行的應(yīng)用層協(xié)議實(shí)現(xiàn),因此Twisted馬上就可為開發(fā)人員所用。
  • 符合RFC規(guī)范,已經(jīng)通過健壯的測試套件證明了其一致性。
  • 能很容易的配合多個網(wǎng)絡(luò)協(xié)議一起使用。
  • 可擴(kuò)展。

21.2 Twisted架構(gòu)概覽

Twisted是一個事件驅(qū)動型的網(wǎng)絡(luò)引擎。由于事件驅(qū)動編程模型在Twisted的設(shè)計哲學(xué)中占有重要的地位,因此這里有必要花點(diǎn)時間來回顧一下究竟事件驅(qū)動意味著什么。

事件驅(qū)動編程是一種編程范式,這里程序的執(zhí)行流由外部事件來決定。它的特點(diǎn)是包含一個事件循環(huán),當(dāng)外部事件發(fā)生時使用回調(diào)機(jī)制來觸發(fā)相應(yīng)的處理。另外兩種常見的編程范式是(單線程)同步以及多線程編程。

讓我們用例子來比較和對比一下單線程、多線程以及事件驅(qū)動編程模型。圖21.1展示了隨著時間的推移,這三種模式下程序所做的工作。這個程序有3個任務(wù)需要完成,每個任務(wù)都在等待I/O操作時阻塞自身。阻塞在I/O操作上所花費(fèi)的時間已經(jīng)用灰色框標(biāo)示出來了。

運(yùn)行服務(wù)器端腳本將啟動一個TCP服務(wù)器,監(jiān)聽端口8000上的連接。服務(wù)器采用的是Echo協(xié)議,數(shù)據(jù)經(jīng)TCP transport對象寫出。運(yùn)行客戶端腳本將對服務(wù)器發(fā)起一個TCP連接,回顯服務(wù)器端的回應(yīng)然后終止連接并停止reactor事件循環(huán)。這里的Factory用來對連接的雙方生成protocol對象實(shí)例。兩端的通信是異步的,connectTCP負(fù)責(zé)注冊回調(diào)函數(shù)到reactor事件循環(huán)中,當(dāng)socket上有數(shù)據(jù)可讀時通知回調(diào)處理。

Applications

Twisted是用來創(chuàng)建具有可擴(kuò)展性、跨平臺的網(wǎng)絡(luò)服務(wù)器和客戶端的引擎。在生產(chǎn)環(huán)境中,以標(biāo)準(zhǔn)化的方式簡化部署這些應(yīng)用的過程對于Twisted這種被廣泛采用的平臺來說是非常重要的一環(huán)。為此,Twisted開發(fā)了一套應(yīng)用程序基礎(chǔ)組件,采用可重用、可配置的方式來部署Twisted應(yīng)用。這種方式使程序員避免堆砌千篇一律的代碼來將應(yīng)用程序同已有的工具整合在一起,這包括精靈化進(jìn)程(daemonization)、日志處理、使用自定義的reactor循環(huán)、對代碼做性能剖析等。

應(yīng)用程序基礎(chǔ)組件包含4個主要部分:服務(wù)(Service)、應(yīng)用(Application)、配置管理(通過TAC文件和插件)以及twistd命令行程序。為了說明這個基礎(chǔ)組件,我們將上一節(jié)的Echo服務(wù)器轉(zhuǎn)變成一個應(yīng)用。

Service

Service就是IService接口下實(shí)現(xiàn)的可以啟動和停止的組件。Twisted自帶有TCP、FTP、HTTP、SSH、DNS等服務(wù)以及其他協(xié)議的實(shí)現(xiàn)。其中許多Service都可以注冊到單獨(dú)的應(yīng)用中。IService接口的核心是:

startService    啟動服務(wù)??赡馨虞d配置數(shù)據(jù),設(shè)定數(shù)據(jù)庫連接或者監(jiān)聽某個端口
stopService     關(guān)閉服務(wù)??赡馨瑢顟B(tài)保存到磁盤,關(guān)閉數(shù)據(jù)庫連接或者停止監(jiān)聽端口

我們的Echo服務(wù)使用TCP協(xié)議,因此我們可以使用Twisted中IService接口下默認(rèn)的TCPServer實(shí)現(xiàn)。

Application

Application是處于最頂層的Service,代表了整個Twisted應(yīng)用程序。Service需要將其自身同Application注冊,然后就可以用下面我們將介紹的部署工具twistd搜索并運(yùn)行應(yīng)用程序。我們將創(chuàng)建一個可以同Echo Service注冊的Echo應(yīng)用。

TAC文件

當(dāng)在一個普通的Python文件中管理Twisted應(yīng)用程序時,需要由開發(fā)者負(fù)責(zé)編寫啟動和停止reactor事件循環(huán)以及配置應(yīng)用程序的代碼。在Twisted的基礎(chǔ)組件中,協(xié)議的實(shí)現(xiàn)都是在一個模塊中完成的,需要使用到這些協(xié)議的Service可以注冊到一個Twisted應(yīng)用程序配置文件中(TAC文件)去,這樣reactor事件循環(huán)和程序配置就可以由外部組件來進(jìn)行管理。

要將我們的Echo服務(wù)器轉(zhuǎn)變成一個Echo應(yīng)用,我們可以按照以下幾個簡單的步驟來完成:

  1. 將Echo服務(wù)器的Protocol部分移到它們自己所歸屬的模塊中去。

  2. 在TAC文件中:

    1. 創(chuàng)建一個Echo應(yīng)用。
    2. 創(chuàng)建一個TCPServer的Service實(shí)例,它將使用我們的EchoFactory,然后同前面創(chuàng)建的應(yīng)用完成注冊。

管理reactor事件循環(huán)的代碼將由twistd來負(fù)責(zé),我們下面會對此進(jìn)行討論。這樣,應(yīng)用程序的代碼就變成這樣了:

echo.py文件:

from twisted.internet import protocol, reactor

class Echo(protocol.Protocol):
    def dataReceived(self, data):
        self.transport.write(data)

class EchoFactory(protocol.Factory):
    def buildProtocol(self, addr):
        return Echo()

twistd

twistd(讀作“twist-dee”)是一個跨平臺的用來部署Twisted應(yīng)用程序的工具。它執(zhí)行TAC文件并負(fù)責(zé)處理啟動和停止應(yīng)用程序。作為Twisted在網(wǎng)絡(luò)編程中具有“內(nèi)置電池”能力的一部分,twistd自帶有一些非常有用的配置標(biāo)志,包括將應(yīng)用程序轉(zhuǎn)變?yōu)槭刈o(hù)進(jìn)程、定義日志文件的路徑、設(shè)定特權(quán)級別、在chroot下運(yùn)行、使用非默認(rèn)的reactor,甚至是在profiler下運(yùn)行應(yīng)用程序。

我們可以像這樣運(yùn)行這個Echo服務(wù)應(yīng)用:

$ twistd –y echo_server.tac

在這個簡單的例子里,twistd將這個應(yīng)用程序作為守護(hù)進(jìn)程來啟動,日志記錄在twistd.log文件中。啟動和停止應(yīng)用后,日志文件內(nèi)容如下:

2011-11-19 22:23:07-0500 [-] Log opened.
2011-11-19 22:23:07-0500 [-] twistd 11.0.0 (/usr/bin/python 2.7.1) starting up.
2011-11-19 22:23:07-0500 [-] reactor class: twisted.internet.selectreactor.SelectReactor.
2011-11-19 22:23:07-0500 [-] echo.EchoFactory starting on 8000
2011-11-19 22:23:07-0500 [-] Starting factory <echo.EchoFactory instance at 0x12d8670>
2011-11-19 22:23:20-0500 [-] Received SIGTERM, shutting down.
2011-11-19 22:23:20-0500 [-] (TCP Port 8000 Closed)
2011-11-19 22:23:20-0500 [-] Stopping factory <echo.EchoFactory instance at 0x12d8670>
2011-11-19 22:23:20-0500 [-] Main loop terminated.
2011-11-19 22:23:20-0500 [-] Server Shut Down.

通過使用Twisted框架中的基礎(chǔ)組件來運(yùn)行服務(wù),這么做使得開發(fā)人員能夠不用再編寫類似守護(hù)進(jìn)程和記錄日志這樣的冗余代碼了。這同樣也為部署應(yīng)用程序建立了一個標(biāo)準(zhǔn)的命令行接口。

Plugins

對于運(yùn)行Twisted應(yīng)用程序的方法,除了基于TAC文件外還有一種可選的方法,這就是插件系統(tǒng)。TAC系統(tǒng)可以很方便的將Twisted預(yù)定義的服務(wù)同應(yīng)用程序配置文件注冊,而插件系統(tǒng)能夠方便的將用戶自定義的服務(wù)注冊為twistd工具的子命令,然后擴(kuò)展應(yīng)用程序的命令行接口。

在使用插件系統(tǒng)時:

  1. 由于只有plugin API需要保持穩(wěn)定,這使得第三方開發(fā)者能很容易地擴(kuò)展軟件。

  2. 插件發(fā)現(xiàn)能力已經(jīng)集成到系統(tǒng)中了。插件可以在程序首次運(yùn)行時加載并保存,每次程序啟動時會重新觸發(fā)插件發(fā)現(xiàn)過程,或者也可以在程序運(yùn)行期間反復(fù)輪詢新插件,這使得在程序已經(jīng)啟動后我們還可以判斷是否有新的插件安裝上了。

當(dāng)使用Twisted插件系統(tǒng)來擴(kuò)展軟件時,我們要做的就是創(chuàng)建IPlugin接口下實(shí)現(xiàn)的對象并將它們放到一個特定的位置中,這里插件系統(tǒng)知道該如何去找到它們。

我們已經(jīng)將Echo服務(wù)轉(zhuǎn)換為一個Twisted應(yīng)用程序了,而將其轉(zhuǎn)換為一個Twisted插件也是非常簡單直接的。在我們之前的Echo模塊中,除了包含有Echo協(xié)議和EchoFactory的定義之外,現(xiàn)在我們還要添加一個名為twistd的目錄,其中還包含著一個名為plugins的子目錄,這里正是我們需要定義echo插件的地方。通過這個插件,我們可以啟動一個echo服務(wù),并將需要使用的端口號作為參數(shù)指定給twistd工具。

from zope.interface import implements

from twisted.python import usage
from twisted.plugin import IPlugin
from twisted.application.service import IServiceMaker
from twisted.application import internet

from echo import EchoFactory

class Options(usage.Options):
    optParameters = [["port", "p", 8000, "The port number to listen on."]]

class EchoServiceMaker(object):
    implements(IServiceMaker, IPlugin)
    tapname = "echo"
    description = "A TCP-based echo server."
    options = Options

def makeService(self, options):
    """
    Construct a TCPServer from a factory defined in myproject.
    """
    return internet.TCPServer(int(options["port"]), EchoFactory())

serviceMaker = EchoServiceMaker()

現(xiàn)在,我們的Echo服務(wù)器將作為一個服務(wù)選項(xiàng)出現(xiàn)在twistd –help的輸出中。運(yùn)行twistd echo –port=1235將在端口1235上啟動一個Echo服務(wù)器。

Twisted還帶有一個可拔插的針對服務(wù)器端認(rèn)證的模塊twisted.cred,插件系統(tǒng)常見的用途就是為應(yīng)用程序添加一個認(rèn)證模式。我們可以使用twisted.cred中現(xiàn)成的AuthOptionMixin類來添加針對各種認(rèn)證的命令行支持,或者是添加新的認(rèn)證類型。比如,我們可以使用插件系統(tǒng)來添加基于本地Unix密碼數(shù)據(jù)庫或者是基于LDAP服務(wù)器的認(rèn)證方式。

twistd工具中附帶有許多Twisted所支持的協(xié)議插件,只用一條單獨(dú)的命令就可以完成啟動服務(wù)器的工作了。這里有一些通過twistd啟動服務(wù)器的例子:

twistd web –port 8080 –path .

這條命令將在8080端口啟動一個HTTP服務(wù)器,在當(dāng)前目錄中負(fù)責(zé)處理靜態(tài)和動態(tài)頁面請求。

twistd dns –p 5553 –hosts-file=hosts

這條命令在端口5553上啟動一個DNS服務(wù)器,解析指定的文件hosts中的域名,這個文件的內(nèi)容格式同/etc/hosts一樣。

sudo twistd conch –p tcp:2222

這條命令在端口2222上啟動一個SSH服務(wù)器。ssh的密鑰必須獨(dú)立設(shè)定。

twistd mail –E –H localhost –d localhost=emails

這條命令啟動一個ESMTP POP3服務(wù)器,為本地主機(jī)接收郵件并保存到指定的emails目錄下。

我們可以方便的通過twistd來搭建一個用于測試客戶端功能的服務(wù)器,但它同樣是可裝載的、產(chǎn)品級的服務(wù)器實(shí)現(xiàn)。

在部署應(yīng)用程序的方式上,Twisted通過TAC文件、插件以及命令行工具twistd的部署方式已經(jīng)獲得了成功。但是有趣的是,對于大多數(shù)大型Twisted應(yīng)用程序來說,部署它們?nèi)匀恍枰貙懸恍┻@類管理和監(jiān)控組件;Twisted的架構(gòu)并沒有對系統(tǒng)管理員的需求呈現(xiàn)出太多的友好性。這也反映了一個事實(shí),那就是對于系統(tǒng)管理員來說Twisted歷來就沒有太多架構(gòu)可言,而這些系統(tǒng)管理員才是部署和維護(hù)應(yīng)用程序的專家。在這方面,Twisted在未來架構(gòu)設(shè)計的決策上需要更積極的征求這類專家級用戶的反饋意見。

21.3 反思與教訓(xùn)

Twisted最近剛剛渡過了其10周年的誕辰。自項(xiàng)目成立以來,由于受2000年早期的網(wǎng)絡(luò)游戲啟發(fā),目前的Twisted已經(jīng)在很大程度上實(shí)現(xiàn)了作為一個可擴(kuò)展、跨平臺、事件驅(qū)動的網(wǎng)絡(luò)引擎的目標(biāo)。Twisted廣泛使用于生產(chǎn)環(huán)境中,從Google、盧卡斯電影到Justin.TV以及Launchpad軟件協(xié)作平臺都有在使用。Twisted中的服務(wù)器端實(shí)現(xiàn)是多個開源軟件的核心,包括BuildBot、BitTorrent以及TahoeLAFS。

Twisted從最初開發(fā)到現(xiàn)在,其架構(gòu)已經(jīng)經(jīng)歷了幾次大的變動。Deferred對象作為一個關(guān)鍵部分被增加了進(jìn)來。如前文所述,這是用來管理延后的結(jié)果以及相應(yīng)的回調(diào)鏈。

還有一個重要的部分被移除掉了,在目前的實(shí)現(xiàn)中已經(jīng)幾乎看不到任何影子了,這就是Twisted應(yīng)用持久化(Twisted Application Persistence)。

Twisted應(yīng)用持久化

Twisted應(yīng)用持久化(TAP)是指將應(yīng)用程序的配置和狀態(tài)保存在一個pickle中。要運(yùn)行采用了這種方案的應(yīng)用需要兩個步驟:

  1. 使用mktap工具創(chuàng)建一個代表該應(yīng)用的pickle(該工具現(xiàn)已廢棄不用)。

  2. 使用twistd命令行工具進(jìn)行unpickle操作,然后運(yùn)行該應(yīng)用。

這個過程是受Smalltalk images的啟發(fā),因?yàn)槲覀冇憛捘欠N臨時性的且難以使用的專用配置語言,不希望它們在項(xiàng)目中不斷擴(kuò)散。我們更希望在Python中表示配置的細(xì)節(jié)。

很快,TAP文件就引入了不必要的復(fù)雜性。修改Twisted中的類并不會使pickle中這些類的實(shí)例得到改變。在pickle對象上使用新版本的類方法或?qū)傩詴r可能會使整個應(yīng)用崩潰。因此“升級版”的概念得以引入,即將pickle對象升級到新的API版本。但這就會出現(xiàn)升級版本的矩陣化現(xiàn)象,出現(xiàn)各種不同版本的pickle對象,因此單元測試時需要維護(hù)涵蓋所有可能的升級路徑。想全面地跟蹤所有的接口變化依然很難,而且容易出錯。

TAP以及相關(guān)的組件全部被廢除了,最終從Twisted中完全剔除掉。取而代之的是TAC文件和插件系統(tǒng)。TAP這個縮寫被重新定義為Twisted Application Plugin(Twisted應(yīng)用插件),如今已經(jīng)很難在Twisted中找到pickle系統(tǒng)的蹤跡了。

我們從TAP的慘敗中得到的教訓(xùn)是:如果可維護(hù)性要達(dá)到合理化的程度,則持久性數(shù)據(jù)就需要有一個明確的模式。更一般的是,我們學(xué)到了如何為項(xiàng)目增加復(fù)雜度:為了解決某個問題而需要引入一個新系統(tǒng)時,我們要正確理解這個方案的復(fù)雜性,并經(jīng)過測試。新系統(tǒng)所帶來的價值應(yīng)該明顯大于其復(fù)雜性。確保了這一點(diǎn)之后我們才能將方案付諸于項(xiàng)目中。

web2:重構(gòu)的教訓(xùn)

雖然這基本上不屬于架構(gòu)設(shè)計上的決策,但從項(xiàng)目管理的角度來看,重寫Twisted的Web實(shí)現(xiàn)對于Twisted的外在形象以及維護(hù)者對代碼庫中其他部分做架構(gòu)改善的能力卻有著長遠(yuǎn)的影響,因此這里值得我們簡單討論一下。

在2000年中期,Twisted的開發(fā)者決定完全重寫twisted.web API,在Twisted代碼庫中將其作為一個單獨(dú)的項(xiàng)目實(shí)現(xiàn),這就是web2。web2將包含許多針對原有twisted.web的改善和提升,包括完全支持HTTP1.1,以及對流式數(shù)據(jù)的API支持。

web2最初只是試驗(yàn)性的項(xiàng)目,但最終被大型項(xiàng)目所采用,甚至意外的得以在Debian系統(tǒng)上打包發(fā)布。twisted.web和web2的開發(fā)一直并行持續(xù)了多年,新用戶常常被這兩個并行的項(xiàng)目搞混,關(guān)于究竟應(yīng)該使用哪種實(shí)現(xiàn)缺乏明確的提示,這使得新用戶很沮喪。轉(zhuǎn)換到web2的情況從未出現(xiàn),終于在2011年開發(fā)者將其從代碼庫中移除,官方主頁上再也看不到它了。web2中做出的一些改進(jìn)也被慢慢地移植回twisted.web中。

Twisted獲得了難以導(dǎo)航且結(jié)構(gòu)混亂,容易使新開發(fā)者感到困惑的“惡名”,這個印象部分歸功于web2。以至于數(shù)年之后,Twisted社區(qū)仍然在同這種不和諧的名聲做斗爭。

我們從web2中汲取的教訓(xùn)是:從頭開始重構(gòu)一個項(xiàng)目通常都是糟糕的主意。但如果必須這么做,請確保開發(fā)者社區(qū)能夠懂得這么做的長遠(yuǎn)意義,而且在用戶社群中要有明確的選擇該使用哪種實(shí)現(xiàn)。

如果Twisted能夠倒退回web2的時代,開發(fā)者們應(yīng)該會對twisted.web做一系列向后兼容型的修改而不是去重構(gòu)。

緊跟互聯(lián)網(wǎng)的浪潮

我們使用互聯(lián)網(wǎng)的方式還在持續(xù)演進(jìn)中。把多種協(xié)議的實(shí)現(xiàn)作為軟件核心的一部分,這個技術(shù)決策使得Twisted背負(fù)了維護(hù)這些協(xié)議的沉重負(fù)擔(dān)。隨著標(biāo)準(zhǔn)的改變以及對新協(xié)議的采納,原有的實(shí)現(xiàn)必須跟著演進(jìn),同時需要嚴(yán)格的保證向后兼容性。

Twisted基本上是一個志愿者驅(qū)動型的項(xiàng)目,項(xiàng)目發(fā)展的限制因素不是技術(shù)社區(qū)的熱情,而在于志愿者的時間。比如說,1999年的RFC 2616中定義了HTTP 1.1規(guī)范,而在Twisted的HTTP協(xié)議實(shí)現(xiàn)中增加對HTTP 1.1的支持卻在2005年才開始,等到完成時已經(jīng)是2009年了。1998年RFC 2460中定義了對IPv6的支持,而Twisted對其的支持還在進(jìn)行中,但是直到2011年都未能合并進(jìn)去。

隨著所支持的操作系統(tǒng)的接口改變,實(shí)現(xiàn)也要跟著演進(jìn)。比如,epoll事件通知機(jī)制是在2002年加入到Linux 2.5.44版中的,Twisted隨之也發(fā)展出基于epoll的reactor事件循環(huán)來利用這個新的系統(tǒng)接口。2007年時,蘋果公司發(fā)布的OS 10.5 Leopard系統(tǒng)中,系統(tǒng)調(diào)用poll的實(shí)現(xiàn)居然不支持外設(shè),對于蘋果公司來說這個問題足以讓他們在系統(tǒng)自帶的Python中屏蔽掉select.poll接口。Twisted不得不自行解決這個問題,并從那時起就對用戶提供文檔說明。

有時候,Twisted的開發(fā)并沒有緊跟網(wǎng)絡(luò)世界的變化,有一些改進(jìn)被移到核心層之外的程序庫中去了。比如Wokkel project,這是對Twisted的Jabber/XMPP支持的改進(jìn)合集,已經(jīng)作為“待合入”的獨(dú)立項(xiàng)目有幾年之久了,但還沒有看到合入的希望。在2009年也曾經(jīng)嘗試過增加WebSocket到Twisted中,因?yàn)闉g覽器已經(jīng)開始采納對新協(xié)議的支持了。但開發(fā)計劃最終卻轉(zhuǎn)到其他外部項(xiàng)目中去了,因?yàn)殚_發(fā)者們決定暫不包含新的協(xié)議,直到IETF把它從草案轉(zhuǎn)變成標(biāo)準(zhǔn)以后再說。

所有這一切都在說明,庫和附加組件的擴(kuò)散有力的證明了Twisted的靈活性和可擴(kuò)展性。通過采用嚴(yán)格的測試驅(qū)動開發(fā)策略以及文檔化和編碼規(guī)范標(biāo)準(zhǔn),這樣做能夠幫助項(xiàng)目避免出現(xiàn)需要“回爐”的情況。在維護(hù)大量所支持的協(xié)議和平臺的同時保持向后兼容性。Twisted是一個成熟、穩(wěn)定的項(xiàng)目,并繼續(xù)保持有非?;钴S的開發(fā)狀態(tài)。

Twisted期待著在下一個十年里成為你遨游互聯(lián)網(wǎng)的引擎。

以上內(nèi)容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號