Python3&Python2,通过zk,Telnet 调用dubbo

python通过zk调用dubbo

前提

  • 安装telnet
  • 配置好python环境
  • 本地zk集群
  • 启动dubbo服务
  • 启动dubbo monitor监控服务
  • 装好python编译器&配置(Python3+Sublime text)

dubbo telnet 原理

  • dubbo 本身提供了一套telnet指令(每个指令被单独封装成了handler)

  • 这些handler,被定义在dubbo-plugin项目的resources/org.apache.dubbo.remoting.telnet.TelnetHandler 文件中
    在这里插入图片描述- 用户通过 telnet host port 可以连接到dubbo
    在这里插入图片描述

  • dubbo 提供了如下指令:ls、ps、cd、pwd、trace、count、invoke

  • 命令介绍:http://www.ibloger.net/article/3407.html

python 调用zookeeper 原理

  • python的zookeeper接口是kazoo
  • 需要通过 pip install kazoo 安装类库
  • 注意:如果使用python3 需要使用pip3

DUBBO BUG!!! Unsupported command: xxx

  • 目前我测试下来 2.7.5 不支持 telnet 操作
  • 原因:由于2.7.5 更改了 handler 的位置却没有改resources文件,所以 调用telnet 会报错 ‘ Unsupported command: xxx’
  • 解决办法:升级到2.7.6或以上版本,或者修改org.apache.dubbo.remoting.telnet.TelnetHandler文件

show me the code

Python3

python 调用zk部分代码
from urllib.parse import unquote

from kazoo.client import KazooClient

# zookeeper的ip和端口,集群 可以随意连接一台
zk = {
    'host': '127.0.0.1',
    'port': 2001
}

class Zookeeper:
    client = None
    service_dict = {}

    class ServiceNotAvailableError(ValueError):
        pass


    def __init__(self, timeout=100):
        # 连接zookeeper
        self.client = KazooClient('%s:%s' % (zk['host'], zk['port']), timeout=timeout)
        self.client.start()

        # 查找所有注册的dubbo服务
        service_list = self.client.get_children('dubbo')
        for service in service_list:
            name = str(service).split('.')[-1]  # 去掉包名,剩下的服务名作为key
            self.service_dict[name] = service  # 此处如果有重名的服务,会覆盖


    def get_service_address(self, service):
        """获取指定服务的注册地址信息"""
        if '.' not in service:
            # 如果传入的服务名不带包名,就从service_dict找到完整服务名
            service = self.service_dict[service]

        uri = 'dubbo/%s' % service
        if not self.client.exists(uri):
            raise ServiceNotAvailableError('服务"%s"不存在' % service)
        elif not self.client.exists('%s/providers' % uri):
            raise ServiceNotAvailableError('服务"%s"没有提供者' % service)
        else:
            providers = self.client.get_children('%s/providers' % uri)
            addrs = []
            for provider in providers:
                addr = str(unquote(provider)).split('/')[2]
                addrs.append((str(addr).split(':')[0], str(addr).split(':')[1], str(addr)))
            return addrs


    def close(self):
        self.client.stop()
        self.client
python 通过telnet 访问dubbo
import json
import telnetlib

class DubboTester(telnetlib.Telnet):
    class Args:

        def __init__(self, service, method, params, host=None, port=0, index=0):
            self.service = service
            self.method = method
            self.params = params
            self.host = host
            self.port = port
            self.index = index

    prompt = 'dubbo>'
    coding = 'utf-8'
    zk = Zookeeper()
    args = None

    def __init__(self, args: Args or dict):
        """
        实例化DubboTester,这一步会连接到指定服务的服务器
        :param args: 可以传Args对象实例,也可以传字典数据,字典最少要包含service、method、params,
            params必须是list类型,list中的元素就是方法所需的参数
        """
        # dict解析成Args对象
        if isinstance(args, dict):
            args = self.__init_args_from_dict(args) if isinstance(args, dict) else args
        address_list = self.zk.get_service_address(args.service)
        if len(address_list) > 1:
            # 对于多节点服务,默认连接第一个节点,可用index指定
            print('——' * 43)
            print('|%s服务有多个地址,使用index参数指定请求地址,默认index=0:|' % str(args.service).center(30, ' '))
            print('-' * 86)
            for i, address in enumerate(address_list):
                print('| %d ==> %s:%s |' % (i, address[0], str(address[1]).ljust(80 - len(address[2]), ' ')))
            print('——' * 43)

        args.host = address_list[args.index][0]
        args.port = address_list[args.index][1]
        print('当前连接地址: %s:%s' % (args.host, args.port))
        self.args = args
        super(DubboTester, self).__init__(host=args.host, port=args.port)
        self.write(b'\n')


    @staticmethod
    def __init_args_from_dict(d):
        service = d.get('service')
        method = d.get('method')
        params = d.get('params', [])
        host = d.get('host')
        port = d.get('port')
        index = d.get('index', 0)
        if port is not None and not isinstance(port, int):
            raise TypeError('port必须是数值类型')
        elif params is not None and not isinstance(params, list):
            raise TypeError('params必须是list类型')
        return DubboTester.Args(service, method, params, port, index)


    @staticmethod
    def __parse_args(args):
        """将参数解析成tenlet命令行调用的字符串格式"""
        if isinstance(args, str) or isinstance(args, dict):
            args = json.dumps(args)
        elif isinstance(args, list):
            tmp = ''
            for arg in args:
                tmp += json.dumps(arg) + ','
            args = tmp[:-1]
        return args



    def command(self, flag, str_=""):
        data = self.read_until(flag.encode())
        self.write(str_.encode() + b'\n')
        return data


    def invoke(self):
        arg = self.__parse_args(self.args.params)
        command_str = "invoke {0}.{1}({2})".format(self.args.service, self.args.method, arg)
        print(self.prompt, command_str)
        self.command(self.prompt, command_str)
        data = self.command(self.prompt, "")
        # [:-6] 截取掉返回结果末尾的'dubbo>'
        data = data.decode(self.coding, errors='ignore')[:-6].strip()
        # 截取掉elapsed及之后的部分
        if 'elapsed' in data:
            data = data[:data.index('elapsed')].strip()
        # 双换行符替换为单换行符
        data = data.replace('\r\n', '\n')
        return data


    def close(self):
        if self.zk:
            self.zk.close()


def run(case: dict):
    try:
        tester = DubboTester(case)
        result = tester.invoke()
        try:
            # 解析结果,结果缩进,支持中文
            result = json.dumps(json.loads(result), ensure_ascii=False, sort_keys=True, indent=4)
        except json.JSONDecodeError as e:
            print(e)
        print('请求结果:\n%s ' % result)
        tester.close()
    except TimeoutError:
        print('连接超时!')
调用接口
if __name__ == '__main__':
    # 输入服务名、方法名和参数v c vb
    case = {
        'service': 'RedisDubboService',
        'method': 'setTest',
        'params': ['a','b',1232311]
    }
    # 执行
    run(case)
java code & log
  • 接口如下:
    在这里插入图片描述
  • python log
    在这里插入图片描述
  • java log
    在这里插入图片描述

Python2

因为线上环境没有Python3,改了一版Python2可以执行的脚本,但是Python2没有zk的支持库

# -*- coding: utf-8 -*-
import json
import telnetlib

class DubboTester(telnetlib.Telnet):

    class Args:

        def __init__(self, service, method, params, host=None, port=0, index=0):
            self.service = service
            self.method = method
            self.params = params
            self.host = host
            self.port = port
            self.index = index

    prompt = 'dubbo>'
    coding = 'utf-8'
    args = None
    conn = None

    def __init__(self, dict):
        """
        实例化DubboTester,这一步会连接到指定服务的服务器
        :param args: 可以传Args对象实例,也可以传字典数据,字典最少要包含service、method、params,
            params必须是list类型,list中的元素就是方法所需的参数
        """
        # dict解析成Args对象
        args = self.__init_args_from_dict(dict)
        self.args = args

    @staticmethod
    def __init_args_from_dict(d):
        service = d.get('service')
        method = d.get('method')
        params = d.get('params', [])
        host = d.get('host')
        port = d.get('port')
        index = d.get('index', 0)
        if port is not None and not isinstance(port, int):
            raise TypeError('port必须是数值类型')
        elif params is not None and not isinstance(params, list):
            raise TypeError('params必须是list类型')
        return DubboTester.Args(service, method, params, host, port, index)

    @staticmethod
    def __parse_args(args):
        """将参数解析成tenlet命令行调用的字符串格式"""
        if isinstance(args, str) or isinstance(args, dict):
            args = json.dumps(args)
        elif isinstance(args, list):
            tmp = ''
            for arg in args:
                tmp += json.dumps(arg) + ','
            args = tmp[:-1]
        return args

    def command(self, flag, str_=""):
    	# print('2.1',flag, str_)
    	self.conn = telnetlib.Telnet()
    	self.conn.open(self.args.host, self.args.port)
    	# print('2.2' , '{}\n'.format(str_).encode())
    	self.conn.write('{}\n'.format(str_).encode())
    	# print('2.3', flag.encode())
        data = self.conn.read_until(flag.encode())
        return data

    def invoke(self):
        arg = self.__parse_args(self.args.params)
        command_str = "invoke {0}.{1}({2})".format(self.args.service, self.args.method, arg)
        print('command_str: %s:%s' % (self.prompt, command_str))
        data = self.command(self.prompt, command_str)
        #print('2.4', data)
        # [:-6] 截取掉返回结果末尾的'dubbo>'
        data = data.decode(self.coding, errors='ignore')[:-6].strip()
        # 双换行符替换为单换行符
        data = data.replace('\r\n', '\n')
        #print('2.5', data)
        return data
    def close(self):
	    self.conn.close
        
def run(dict):
    tester = DubboTester(case)
    result = tester.invoke()
    print('请求成功,结果如下:')
    print(result)
    tester.close()

if __name__ == '__main__':
    # 输入服务名、方法名和参数v c vb
    host = '127.0.0.1'
    port = 20882
    service = 'IUserService'
    method = 'setMiniBackCard'

    jsonarr = '[{"uid":1202302,"url":"https://www.baidu.com","time":16723080830},{"uid":2202302,"url":"https://www.ccccc.com","time":17723080831}]'

    # 循环调用
    arr = json.loads(jsonarr);
    for item in arr :
        case = {
            'host': host,
            'port': port,
            'service': service,
            'method': method,
            'params': [item.get('uid'),item.get('url'),item.get('time')]
        }
        # 执行b
        run(case)

s

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值