ITKeyword - 技术文章推荐分享

首页 > 一个简单RPC框架是如何炼成的(VI)——引入服务注册机制

一个简单RPC框架是如何炼成的(VI)——引入服务注册机制

标签: python, RPC,

相关推荐:一个简单RPC框架是如何炼成的(II)——制定RPC消息

开局篇我们说了,RPC框架的四个核心内容RPC数据的传输。RPC消息 协议RPC服务注册RPC消息处理下面,我们先看一个普通的过程调用class Client(object): def __init__(self): self.remote = None ## # 内部是委托给远程

开局篇我们说了,RPC框架的四个核心内容RPC数据的传输。RPC消息 协议RPC服务注册RPC消息处理接下来处理RPC服务的注册机制。所谓注册机制,就是Server需要声明支持哪些rpc方法,然后当客户端发送调用某个声明的rpc方法之后,服务端能自动找到执行该请求的具体方法。以实际的例子为例,这是现在server端处理RPC请求的代码

def procRequest(self):

# 循环读取并处理收到的客户端请求

while True:

req = self.conn.recv()

rsp = Response()

rsp.id = req.id

if req.command == 'sayHello':

rsp.result = self.sayHello()

elif req.command == 'whoAreYou':

rsp.result = self.whoAreYou()

else:

raise Exception("unknown command")

self.conn.send(rsp)上面的代码有一个很不好的地方,很难稳定。Server端每次新增一个支持的rpc方法,就要修改这个procRequest方法。有什么办法可以避免吗?有,就是引入服务注册机制。在这里,实际就是将command与具体的function object绑定起来,说穿了就是生成一个dict,{‘sayHello’ : self.sayHello,

'whoAreYou': self.whoAreYou}。 有这样的dict之后,收到req 之后,只要提取出command字段,然后从dict中找出对应的function,调用该function即可。基本想法已定,首先我们实现一个比较原始的服务注册机制。 这个实现很简单,self.services就是上面的dict。通过register()去注册服务,通过get_service()去获取服务名对应的functionclass ServiceRegister(object):

'''

@服务注册

不考虑线程安全,这里简化起见,也不引入反射机制。

'''

def __init__(self):

'''

Constructor

'''

self.services = {}

## 注册具体的服务

#

@param servicename: 服务名

#

@param obj: 具体的对象

def register(self, obj, servicename):

if servicename in self.services:

print('warning: %s is already registered' % servicename)

else:

self.services[servicename] = obj

def get_service(self, servicename):

return self.services[servicename]

def list_service(self, servicename=None):

if servicename:

return str({servicename, self.services[servicename]})

else:

return str(self.services)使用时,就是这个样子的服务注册:self.services.register(self.sayHello, 'Server.sayHello', )

self.services.register(self.whoAreYou, 'Server.whoAreYou')

self.services.register(self.add, 'Server.add')服务查找def proc(self, req):

rsp = Response()

rsp.id = req.id

rsp.result = ServiceCaller.call(self.services.get_service(req.command), req.parameter)......上面serviceCaller的实现,就是在RPC消息,实现带参数的RPC请求中,提到的 func(**args)的技巧class ServiceCaller():

def __init__(self):

pass

@classmethod

def call(cls, caller, parameter):

if not parameter or len(parameter) == 0:

return caller()

return caller(**parameter)下面我再

相关推荐:一个简单RPC框架是如何炼成的(III)——实现带参数的RPC调用

上一篇,我们制定了一个很简单的RPC消息 的格式,但是还遗留了两个问题我们并没有实现相应的encode和decode方法,没有基于可以跨设备的字符串传输,而是直接的内存变量传递。现在的RPC request不支持带参数的请求命令。如add(a, b), 如何在RPC消息中描

引入一个自动注册服务的实现直接上代码class AutoServiceRegister(AbstractServiceRegister):

def register_class(self, obj, predicate=None):

if not (hasattr(obj, '__class__') and inspect.isclass(obj.__class__)):

return False

servicename = obj.__class__.__name__

for (name, attr) in inspect.getmembers(obj, predicate):

# 系统方法或者私有方法,不添加

if name.startswith('__') or name.startswith('_' + servicename + '__'): continue

#print(name)

if inspect.ismethod(attr): self.register_method(attr)

elif inspect.isfunction(attr): self.register_function(attr, servicename)

return True使用if __name__ == '__main__':

class AServer(object):

def __init__(self):

pass

def sayHello(self):

return 'Hello World'

def whoAreYou(self):

return 'I am server'

def __kaos(self):

pass

def _kaos(self):

pass

obj = AServer()

service = AutoServiceRegister()

print(service.register_class(obj))

print(service.list_services())

print(service.get_service('AServer.sayHello')) 执行结果如下True{'AServer': {'sayHello': <bound method AServer.sayHello of <__main__.AServer object at 0x000000000294EA90>>, 'whoAreYou': <bound method AServer.whoAreYou of <__main__.AServer object at 0x000000000294EA90>>, '_kaos': <bound method AServer._kaos of <__main__.AServer object at 0x000000000294EA90>>}}<bound method AServer.sayHello of <__main__.AServer object at 0x000000000294EA90>>详细说明 一下原理,利用了类似的反射的技术。有兴趣的同学可以先去了解一下inspectregister_class表示自动搜索一个类对象中的成员方法,并将其作为server端的rpc方法注册进去。以上面AServer为例, 会自动将sayHello, whoAreYou 这两个方法自动注册进来。同时像__init__, __kaos, _kaos之类的系统固有方法,或者私有方法,会自动剔除。注册时,传入的参数obj必须是class的instance,也就是类实例。虽然在python中,也支持类对象,但如果直接传递类对象,就会遇到如何初始化的难题。所以这里一致要求,必须是类的实例。if not (hasattr(obj, '__class__') and inspect.isclass(obj.__class__)):

return False类实例的特点就是,包含__class__成员,而且__class__成员的值就是该类的类对象。inspect.isclass就是检测是不是类对象inspect.getmembers()返回的是类对象的所有成员,包括系统固有方法以及私有方法所以,先要将系统方法和私有方法剔除,然后通过inspect,检查该成员是不是真的是function,就是可以被调用的。如果是,就注册进来register_fucntion, register_method与普通的服务注册基本一样。就是添加(key,value)对。总结:1. 引入服务注册的方式也是为了代码解耦,将req的处理与具体的req消息内容解耦。2. 上面我们 引入了两种服务注册的方式,一种方式是普通的方式,逐个添加方法。另一种方式通过python的“反射”技术,自动查找一个类里面的方法,并自动添加。3. 方案还是很粗糙的,实际有很多优化的地方。

相关推荐:一个简单RPC框架是如何炼成的(V)——引入传输层

开局篇我们说了,RPC框架的四个核心内容RPC数据的传输。RPC消息 协议RPC服务注册RPC消息处理 接下来处理数据传输。实际应用场景一般都是基于socket。socket代码比较多,使用起来也比较麻烦。而且具体的传输通道使用socket或者其他的方式,如更上

开局篇我们说了,RPC框架的四个核心内容RPC数据的传输。RPC消息 协议RPC服务注册RPC消息处理接下来处理RPC服务的注册机制。所谓注册机制,就是Server需要声明支持哪些rpc方法,然后当...

------分隔线----------------------------