python 64式: 第1式 编写rpc的call和cast

myclient.py内容如下

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @File    : myclient.py
# @Software: PyCharm

'''

参考文章:
http://blog.csdn.net/happyanger6/article/details/54777429
https://docs.openstack.org/oslo.messaging/ocata/rpcclient.html

关键:
1 RPC Client基础
oslo_messaging.RPCClient(transport, target, timeout=None,, version_cap=None, serializer=None, retry=None)
作用:调用远程RPC服务的类
参数: transport: rpc底层通信,支持rabbit,qpid
     target: 消息最终发送的地方
            形式:target(exchange,topic,server):
            参数:exchange:topic属于的范围,默认为配置文件的control_exchange
                topic: 可被远程调用的多个方法
                server:消息目的地服务器
2 RPC Call方法
oslo_messaging.RPCClient.call(ctxt, method, **kwargs)
含义:call方法是远程过程调用带有返回值的方法
特点:阻塞直到服务端返回结果
参数: ctxt:上下文字典,可为空
     method:被调用的方法名
     kwargs:调用该方法传入的参数
返回值:返回被调用远程方法的结果

3 RPC Cast方法
oslo_messaging.RPCClient.cast(ctxt, method, **kwargs)
含义:cast方法是远程过程调用,不带有返回值的方法
参数: ctxt:上下文字典,可为空
     method:被调用的方法名
     kwargs:调用该方法传入的参数
返回值:无

4 RPC prepare方法
oslo_messaging.RPCClinet.prepare(exchange, topic, namespace, version, server)
作用:就是覆盖RPCClient初始化的一些属性


5 RPC总结:
实际就是一个远程调用,客户端通过rpc调用服务端的方法。
通过指定方法名和对应参数来进行调用;


RPCClient端调用过程:
1) 通过配置文件获取transport,指定topic初始化target,
2) 用transport和target初始化RPCClient
3) 最后调用RPCClientr的call方法或者cast方法

RPCServer端调用过程:
1) 根据配置初始化transport,根据topic,server等初始化target
2) 指定endpoints数组,每个元素是一个类实例
3) 用transport,target,endpoints,executor来构造rpc server
4) 执行rpc server的start()方法
注意: 客户端和服务端通过target进行连接,都需要指明topic参数。
'''

from oslo_config import cfg
import oslo_messaging as messaging


def rpcCall():
    # 消息中间件,rabbitMQ或者Qpid等
    transport = messaging.get_transport(cfg.CONF)

    target = messaging.Target(topic='test')
    client = messaging.RPCClient(transport, target)
    ret = client.call(ctxt={},
                      method='processCall',
                      name='hello rpc call')
    print "######## End call, result: %s" %  ret

def rpcCast():
    transport = messaging.get_transport(cfg.CONF)
    target = messaging.Target(topic='test')
    client = messaging.RPCClient(transport, target)
    cctx = client.prepare(namespace='control', version='2.0')
    cctx.cast({}, 'processCast', name='hello rpc cast')
    print "######## End cast"

def process():
    rpcCall()
    rpcCast()

if __name__ == "__main__":
    process()

myserver.py内容如下

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @File    : myserver.py
# @Software: PyCharm

from oslo_config import cfg
import oslo_messaging as messaging


'''
参考:
https://docs.openstack.org/ironic/latest/_modules/oslo_messaging/rpc/server.html

关键:
1 总结初始化RPC Server步骤:
1) 根据配置初始化transport,根据topic,server等初始化Target
2) 指定endpoints数组,每个元素是一个类实例
3) 用transport,target,endpoints,executor来构造rpc server
4) 执行rpc server的start()方法

2 get_rpc_server方法分析
    oslo_messaging.get_rpc_server(transport, target, endpoints, executor='blocking')
    作用:构建一个RPC服务器
    参数:
        transport: rpc通信,支持rabbit,qpid;可通过oslo.messaging.get_transport来获得transport对象实例的句柄
                   从cfg对象中读取transport_url,rpc_backend,control_exchange信息来构造Transport对象,
                   其中rpc_backend默认值: rabbit; control_exchange默认值:openstack
        target: 封装消息目的地所有信息,包含exchange, topic, server, namespace, version等信息
                
        endpoints: 端口数组,每个元素是类对象
        executor:消息执行器,可选:eventlet和threading。决定消息如何收到和分发
                eventlet:
                threading:协程处理消息接收,不阻塞
                blocking:阻塞,直到调用stop()退出
        serializer:可选的实体序列化器

3 RPCServer和RPCClient中关于target部分注意点
注意:每个endpoint可能会有一个target属性,有namespace和version字段
默认是 null namespace和1.0版本,用来兼容不同的topic创建的Target构造的RPCClient
调用,样例如下。
class RpcCastEndpoint(object):
    target = messaging.Target(namespace='control',version='2.0')
因为有的RPC Client是用下面方式创建:
    client = messaging.RPCClient(transport, target)
    cctx = client.prepare(namespace='control', version='2.0')
所以两边要匹配
'''

class RpcCastEndpoint(object):
    '''
    注意:每个endpoint可能会有一个target属性,有namespace和version字段
    默认是 null namespace和1.0版本,用来兼容不同的topic创建的Target构造的RPCClient
    调用
    '''
    target = messaging.Target(namespace='control',version='2.0')

    def __init__(self):
        pass

    def processCast(self, ctx, name):
        # print "####### RpcCastEndpoint.processCast##########"
        print name


class RpcCallEndpoint(object):
    def __init__(self):
        pass

    def processCall(self, ctx, name):
        # print "####### RpcCallEndpoint.processCall"
        print name
        return name


def startRpcServer():
    transport = messaging.get_transport(cfg.CONF)
    target = messaging.Target(topic='test',
                              server='server1')
    endpoints = [
        RpcCastEndpoint(),
        RpcCallEndpoint(),
    ]
    server = messaging.get_rpc_server(transport, target, endpoints,
                                      executor='blocking')
    server.start()
    server.wait()


def process():
    startRpcServer()

if __name__ == "__main__":
    process()

先执行:

python myserver.py

然后执行

python myclient.py

即可显示最终结果


猜你喜欢

转载自blog.csdn.net/qingyuanluofeng/article/details/80546961