firefly使用了twisted的pb 来实现rpc:
http://twistedmatrix.com/documents/current/core/howto/pb-usage.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
|
服务端 #!/usr/bin/env python # Copyright (c) Twisted Matrix Laboratories. # See LICENSE for details. from
twisted.spread import pb
from
twisted.internet import reactor
class
One(pb.Root):
def remote_takeTwo(self, two):
print "received a Two called" , two
print "telling it to print(12)"
two.callRemote( "print" , 12)
reactor.listenTCP(8800, pb.PBServerFactory(One())) reactor.run() 客户端 #!/usr/bin/env python # Copyright (c) Twisted Matrix Laboratories. # See LICENSE for details. from
twisted.spread import pb
from
twisted.internet import reactor
class
Two(pb.Referenceable):
def remote_print(self, arg):
print "Two.print() called with" , arg
def main(): two = Two()
factory = pb.PBClientFactory()
reactor.connectTCP( "localhost" , 8800, factory)
def1 = factory.getRootObject()
def1.addCallback(got_obj, two) # hands our ‘two‘
to the callback
reactor.run()
def got_obj(obj, two): print "got One:" , obj
print "giving it our two"
obj.callRemote( "takeTwo" , two)
main() |
1.客户端通过factory.getRootObject() 获取def,并增加回调函数。其第一个参数为pb.Root(未证实),然后借助callRemote方法条用服务端的东西
2.可以在客户端首次连接的时候,将客户端的Referenceable传给服务端。。服务端进行保存。。之后需要像客户端发送消息的时候。。只要使用客户端的callRemote就OK了
root.py 实现PB的server功能
node.py 实现PB的client功能。
child.py 每个client连接上root都会初始化一个child来保存该client的相关信息,并且将这些child通过manager来管理。
manager.py 管理root的child,通过一个字典self._childs = {},实现一个增删改的小管理器。
reference.py 如果你看了前面twisted官网的介绍就会知道,node只要实例化一个 pb.Referenceable 类,并把它传递给root,那么root就能够把这个pb.Referenceble当成句柄来远程调用client的函数。
下面我们看看firefly的实现。
1.实例化客户端node,实例了客户端工厂,_reference和name
2.客户端建立连接:node.connect ,并条用了服务端的takeProxy。建立了通道
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
def callRemote(obj,funcName,*args,**kw): ‘‘ ‘远程调用
@param funcName: str 远程方法
‘‘ ‘
return
obj.callRemote(funcName, *args,**kw)
。。。。。。 。。。。。。 def takeProxy(self):
‘‘ ‘像远程服务端发送代理通道对象
‘‘ ‘
deferedRemote = self._factory.getRootObject()
deferedRemote.addCallback(callRemote, ‘takeProxy‘ ,self._name,self._reference)
|
2.服务端的takeProxy。根据第一次传过来的客户端名称和reference实例化了child,并保存到childManage中
3.执行了首次连接处理。doChildConnect。。请看rootapp.py.如果不看这里你一定会很奇怪,gate的root怎么和其他的server连接起来的。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
def _doChildConnect(name,transport): "" "当server节点连接到master的处理
"" "
server_config = GlobalObject().json_config. get ( ‘servers‘ ,{}). get (name,{})
remoteport = server_config. get ( ‘remoteport‘ ,[])
child_host = transport.broker.transport.client[0]
root_list = [rootport. get ( ‘rootname‘ ) for
rootport in
remoteport]
GlobalObject().remote_map[name] = { "host" :child_host, "root_list" :root_list}
#通知有需要连的node节点连接到此root节点
for
servername,remote_list in
GlobalObject().remote_map.items():
remote_host = remote_list. get ( "host" , "" )
remote_name_host = remote_list. get ( "root_list" , "" )
if
name in
remote_name_host:
GlobalObject().root.callChild(servername, "remote_connect" ,name,remote_host)
#查看当前是否有可供连接的root节点
master_node_list = GlobalObject().remote_map.keys()
for
root_name in
root_list:
if
root_name in
master_node_list:
root_host = GlobalObject().remote_map[root_name][ ‘host‘ ]
GlobalObject().root.callChild(name, "remote_connect" ,root_name,root_host)
|
4.服务端调用客户端。root.callChildByName.会在childManager中找到child并使用其中的reference,最终条用代码为:ProxyReference(pb.Referenceable):中的
1
2
3
4
|
def remote_callChild(self, command,*arg,**kw): ‘‘ ‘代理发送数据
‘‘ ‘
return
self._service.callTarget(command,*arg,**kw)
|
5.客户端条用,服务端使用,node.callRemote..其中最终使用的方法为:root.py中的。
def remote_callTarget(self,command,*args,**kw): ‘‘‘远程调用方法 @param commandId: int 指令号 @param data: str 调用参数 ‘‘‘ data = self.service.callTarget(command,*args,**kw) return data
6.从上可以看到。。使用service的意义何在了。。。