开局篇我们说了。RPC框架的四个核心内容

  1. RPC数据的传输
  2. RPC消息 协议
  3. RPC服务注冊
  4. RPC消息处理

接下来处理RPC服务的注冊机制。所谓注冊机制,就是Server须要声明支持哪些rpc方法。然后当client发送调用某个声明的rpc方法之后,服务端能自己主动找到运行该请求的详细方法。以实际的样例为例。这是如今server端处理RPC请求的代码

    def procRequest(self):
# 循环读取并处理收到的client请求
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就可以。







基本想法已定,

首先我们实现一个比較原始的服务注冊机制。

这个实现非常easy。self.services就是上面的dict。通过register()去注冊服务。通过get_service()去获取服务名相应的function

class 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)

以下我再引入一个自己主动注冊服务的实现

直接上代码
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>>

具体说明 一下原理,利用了类似的反射的技术。

有兴趣的同学能够先去了解一下inspect

  • register_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框架是怎样炼成的(VI)——引入服务注冊机制的更多相关文章

  1. 一个简单RPC框架是怎样炼成的(V)——引入传输层

    开局篇我们说了,RPC框架的四个核心内容 RPC数据的传输. RPC消息 协议 RPC服务注冊 RPC消息处理    接下来处理传输数据.实际应用场景一般都是基于socket.socket代码比較多, ...

  2. 一个简单RPC框架是怎样炼成的(I)——开局篇

    开场白,这是一个关于RPC的相关概念的普及篇系列,主要是通过一步步的调整,提炼出一个相对完整的RPC框架. RPC(Remote Procedure Call Protocol)--远程过程调用协议, ...

  3. 一个简单RPC框架是怎样炼成的(II)——制定RPC消息

    开局篇我们说了,RPC框架的四个核心内容 RPC数据的传输. RPC消息 协议 RPC服务注冊 RPC消息处理 以下,我们先看一个普通的过程调用 class Client(object): def _ ...

  4. 一个简单RPC框架是怎样炼成的(IV)——实现RPC消息的编解码

    之前我们制定了一个非常easy的RPC消息 的格式,可是还遗留了两个问题,上一篇解决掉了一个.还留下一个 我们并没有实现对应的encode和decode方法,没有基于能够跨设备的字符串传输,而是直接的 ...

  5. Java实现简单RPC框架(转)

    一.RPC简介 RPC,全称Remote Procedure Call, 即远程过程调用,它是一个计算机通信协议.它允许像本地服务一样调用远程服务.它可以有不同的实现方式.如RMI(远程方法调用).H ...

  6. 一个入门rpc框架的学习

    一个入门rpc框架的学习 参考 huangyong-rpc 轻量级分布式RPC框架 该程序是一个短连接的rpc实现 简介 RPC,即 Remote Procedure Call(远程过程调用),说得通 ...

  7. RPC笔记之初探RPC:DIY简单RPC框架

    一.什么是RPC RPC(Remote Procedure Call)即远程过程调用,简单的说就是在A机器上去调用B机器上的某个方法,在分布式系统中极其常用. rpc原理其实很简单,比较容易理解,在r ...

  8. 基于Netty和SpringBoot实现一个轻量级RPC框架-协议篇

    基于Netty和SpringBoot实现一个轻量级RPC框架-协议篇 前提 最近对网络编程方面比较有兴趣,在微服务实践上也用到了相对主流的RPC框架如Spring Cloud Gateway底层也切换 ...

  9. 基于Netty和SpringBoot实现一个轻量级RPC框架-Server篇

    前提 前置文章: Github Page:<基于Netty和SpringBoot实现一个轻量级RPC框架-协议篇> Coding Page:<基于Netty和SpringBoot实现 ...

随机推荐

  1. 关于Future.cancel(mayInterruptIfRunning)方法的参数的问题

    mayInterruptIfRunning设成false话,不允许在线程运行时中断,设成true的话就允许. 可以参考下面的代码来理解,如果设为false的话,会打印到99999,如果设成true的话 ...

  2. HttpClient4.3教程 第二章 连接管理

    2.1.持久连接 两个主机建立连接的过程是很复杂的一个过程,涉及到多个数据包的交换,并且也很耗时间.Http连接需要的三次握手开销很大,这一开销对于比较小的http消息来说更大.但是如果我们直接使用已 ...

  3. Visual studio之C# 调用系统软键盘(外部"osk.exe")

    背景 App需要调用系统软键盘输入数据,自己去实现软键盘有些复杂,现在又是急需,没时间去研究实现软键盘,所以只能调用系统软键盘. 正文 需要添加命名空间, using System.Diagnosti ...

  4. MAC-Zsh安装与使用——终极Shell

    前言:Zsh可配置性强,用户可以自定义配置,个性化强.Zsh tab补全更强大,该功能可以让我们节约很多时间.Zsh 还有代码高亮功能,使得代码更好看了,显得逼格更高.Zsh 还有很多强大的功能,这里 ...

  5. join和countDownLatch原理及区别详解

    先上结论 原理 join 原理:在当前线程中调用另一个线程线程 thread 的 join() 方法时,会调用该 thread 的 wait() 方法,直到这个 thread 执行完毕(JVM在 ru ...

  6. Mac Xcode下配置OpenGL

    暂时搁置一下iOS,又要去弄一些杂七杂八的东西了,毕竟是学校的作业,还是要完成的. 作业是让我们用OpenGL做一个茶壶- -.而且要三维立体能旋转的那种. 好吧这些都不是重点,重点是我最终决定在Ma ...

  7. 最实用、最常用的jQuery代码片段

    // chinacoder.cn JavaScript Document $(document).ready(function() { //.filter(":not(:has(.selec ...

  8. git 简单使用规范

    分支管理办法 创建一个主仓库dev 每个成员fork一份dev分支 在自己fork出来的代码里做开发 开发完成后发出一个合并请求 pull request,等待被其他有合并权限的同事合并代码,合并代码 ...

  9. Myeclipse10安装git 完美解决-费元星

    1. 拥有自己的github版本库 这年头,不在GitHub上弄几个项目都不好意思跟人家打招呼. 首先,进入GitHub注册账号,话说人家这页面做的那叫一个舒服啊. 然后,登陆并创建自己的版本库(Re ...

  10. SecureCRT终端上使用spark-shell时按退格键无反应的解决方法

    问题:用SecureCRT远程连接至Spark集群,启动spark-shell却发现输错命令后却无法用退格键删除. 解决方法: 第一步: 在SecureCRT的菜单栏选择“OPtions(选项)”按钮 ...