我也是不久前刚开始自学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 开始监听