我也是不久前剛開始自學python的,前不久剛寫了個小Demo,Demo中用到了Twisted這一塊,所以就自己隨手記錄了一下在Demo中的心得,希望對python新手有一定的幫助,同時如果在以下有講的不對的地方,也希望博友們能指出,小弟會感激不盡。
python中對客戶端和服務端的通信提供了很好的支持,Twisted封裝了大量有關python通信技術。而通信時對用戶的驗證也是很有必要的,這樣可以保證服務端的安全。twisted提供cred模塊, 將用戶校驗和業務邏輯分開以降低系統的耦合性。例如郵件服務中的pop3和imap可以使用同一套的驗證邏輯和不同的業務邏輯。在Twisted中, pop3, imap, ssh、ftp和PB服務都使用了twisted.cred來進行驗證。
其中,twisted.cred驗證最重要的三個模塊爲:Portal、checkers和credentials,下面我用Demo中的代碼來進行分析和講解。
首先必須導入twisted.cred模塊
from twisted.cred import portal,checkers,credentials
Main:下面是服務端Main裏面運行的幾行代碼
p = portal.Portal(Realm()) # line 1
p.registerChecker(UserChecker()) # line 2
f = pb.PBServerFactory(p) # line 3
reactor.listenTCP(8206, f) # line 4
reactor.run() # line 5
Main中line 1 實例化了一個Portal對象,Portal作爲入口,每一次用戶服務都和Portal進行交互,portal.Portal()帶了一個參數,該參數其實是一個類,該類繼承了portal.IRealm接口,portal.IRealm接口其實就是一個對象認證系統,每次用戶驗證完成之後,都將會通過該接口將服務端協議返回給客戶端,供客戶端調用,下面有代碼可以供參考
class Realm:
implements(portal.IRealm) # 實現 portal中的IRealm接口 ,implements關鍵字由from zope.interface import implements導入
def requestAvatar(self, user, mind, *interfaces): # 重寫IRealm接口內的requestAvator方法,該方法有4個參數,第二個參數是由
# checkers.ICredentialsChecker接口的requestAvatarId方法返回用於識別用戶唯一性的ID,後面會講
# 到;第三個參數其實就是一個客戶端對象,該客戶端對象由客戶端的pb.PbClientFactory的Login()方法
# 傳入,該對象必須繼承了pb.Referenceable或者是pb.Avator協議,一旦驗證通過,服務端就可以通過該
# 對象協議與客戶端通信,調用客戶端方法;第四個參數是一個list, 用於決定返回的avatar類型, 通常
# 只有一個元素pb.IPerspective
if pb.IPerspective not in interfaces: # 檢測pb.IPerspective是否在list中,如果不在當中,就拋出異常
raise NotImplementedError
def remove(): del userlist[user.account]
user.client = mind # 將每次驗證通過後的客戶端協議保存在user對象中,後面可以對任意處於連接狀態的客戶端進行調用
return pb.IPerspective, Persective(mind), remove # 該方法返回了一個三個元素的元祖,第一個元素爲一個avator類型;第二個參數是一個協議對
# 象,該對象必須繼承自pb.Refrenceable或者是pb.Avator協議,該對象返回至客戶端,客戶端
# 就可以通過該協議與服務端進行通信,調用服務器方法;第三個元素返回了一個回調函數,該
# 函數在客戶端與服務端斷開連接的時候被觸發
以下是第二個參數Perspective類代碼:
# 該類遠程調用客戶端的方法
class ClientAvator(pb.Referenceable): # 繼承自 pb.Referenceable , 也可繼承自 pb.Avator
def __init__(self,client):
self.client = client
def callSelfRemote(self,clientFunName): # 遠程調用本次驗證通過後的用戶的客戶端方法
self.client.callRemote(clientFunName)
def callUserRemote(self,clientFunName,user): # 遠程調用其它驗證通過後的用戶的客戶端方法
user.client.callRemote(clientFunName)
def popupUserOnlineDlg(self,user=None):
if user:
self.callUserRemote("popupUserOnlineDlg",user)
else:
self.callSelfRemote("popupUserOnlineDlg")
# 該類的方法供客戶端遠程調用
class Persective(ClientAvator): # 繼承了ClientAvator,ClientAvator繼承自 pb.Referenceable
def __init__(self,client):
ClientAvator.__init__(self,client=client)
def remote_NotifyOthserOnlineUsers(self): # 注意遠程調用的方法前綴,如果是繼承pb.Refrenceable協議,對應的前綴就爲remote_,如果繼承的是pb.Avator協
# 議,前綴就是perspective_
for u in userlist.itervalues():
self.popupUserOnlineDlg(u)
Main中line 2就是向Portal裏面注入一個用戶登錄時進行驗證的憑據,也就是驗證邏輯,UserChecker對象繼承了checkers.ICredentialsChecker接口,該接口支持用戶名/密碼對、密鑰等多種認證方式,其中的用戶驗證邏輯就可以通過重寫接口內的 requestAvatarId方法實現,下面有代碼可以供參考
class UserChecker:
implements(checkers.ICredentialsChecker) # 繼承了 checkers.ICredentialsChecker 接口
credentialInterfaces = (credentials.IUsernamePassword,credentials.IUsernameHashedPassword) # 指明認證方式,這裏指明的是用戶名/密碼對的認證方式
def requestAvatarId(self,credentials): ############### 重寫 checkers.ICredentialsChecker接口的 requestAvatorId方法,該方法有2個參數,第二個參數
# 是由客戶端pb.PBClientFactory 的Login() 方法傳過來的參數,關於Login()方法,後面會詳細的
# 爲您講解
accountPwd = credentials.username.split(',')
if len(accountPwd)!=2:
return defer.fail(u'非法的登錄參數!')
account,pwd = accountPwd
if int(account) in userlist:
return defer.fail(u"帳號已在別處登錄")
remarks,user = UserLogin(account,pwd)
if user:
userlist[user.account] = user
return defer.succeed(user) # 驗證通過後,將user對象傳遞給IRealm的requestAvator方法處理
else:
return defer.fail(remarks) # 驗證失敗,IRealm的requestAvator方法不執行,直接將錯誤信息返回至客戶端
3、4、5三行代碼,在我的之前的博文當中已經有了詳細講解,不是很清楚的可以去看下。
Main 中 line 3 實例化了一個服務工廠PbServerFactory,該工程實例化時接受了一個Portal實例化後的對象
Main 中 line 4 設置了監聽的工廠及監聽端口
Main 中 line 5 開始監聽