简单学习rpc -- thrift demos

来源:互联网 发布:企业软件收费模式 编辑:程序博客网 时间:2024/06/06 20:07

简单介绍:

  1. fb开源的远程服务调用(rpc)框架(序列化和rpc一站式解决)。
  2. 接口描述语言(IDL)创建服务,支持跨语言服务开发,透明通信(利用代码生成引擎)。
  3. 序列化二进制数据传输。
  4. 用到的数据结构全部静态化,需要事先定义,中途修改需要重新编译。
  5. 快速的开发socket server和client。

start thrift

官方步骤

windows:
1. 下载trift compiler for windows
2. git clone https://git-wip-us.apache.org/repos/asf/thrift.git thrift
3. 进入thrift python库的目录:thrift/lib/py
4. 安装python组件 python setup.py install,安装成功后会在当前目录生成/build目录,发现/build/lib和/build/lib.win32-3.5两个目录下都生成了thrift包,暂时不清楚其区别(一个是通用版?一个是win32下的3.5版本?还有在/thrit/lib/py下存在一个/src目录,也包含了thrift python所需的文件,这几个的区别暂时不清楚)。
5. 编写pingpong.thrift文件

service PingPong {    string ping(),}service DingDang {    string ding(),}


6. 利用下载的thrift compiler进行编译。thrift-0.10.0.exe --out gen --gen py pingpong.thrift,成功后会生成/gen目录,下面有所需的PingPong包和py文件。
7. 将生成的gen包拷贝到项目下。
8. 编写服务器文件server.py

#!/usr/bin/python# -*- coding:utf-8 -*-from thrift import Thriftfrom thrift.TMultiplexedProcessor import TMultiplexedProcessorfrom thrift.transport import TSocketfrom thrift.transport import TTransportfrom thrift.protocol import TBinaryProtocolfrom thrift.protocol import TCompactProtocolfrom thrift.server import TServerfrom gen.pingpong import PingPong, DingDangimport socketclass PingPongServiceServer(object):    def ping(self):        print(socket.gethostbyname(socket.gethostname()))        return 'pong'class DingDangServiceServer(object):    def ding(self):        print(socket.gethostbyname(socket.gethostname()))        return 'dang'# commontransport = TSocket.TServerSocket('127.0.0.1', 8080)  # 通信socket并设置服务端口tfactory = TTransport.TBufferedTransportFactory()  # 传输工厂类pfactory = TBinaryProtocol.TBinaryProtocolFactory()  # 二进制协议工厂类# pfactory = TCompactProtocol.TCompactProtocolFactory()# processorspingpong_handler = PingPongServiceServer()  # 服务实现类实例pingpong_processor = PingPong.Processor(pingpong_handler)dongdang_handler = DingDangServiceServer()dingdang_processor = DingDang.Processor(dongdang_handler)# single service# server = TServer.TSimpleServer(pingpong_processor, transport, tfactory, pfactory)# multi service 多服务multi_processor = TMultiplexedProcessor()multi_processor.registerProcessor('pingpong_service', pingpong_processor)multi_processor.registerProcessor('dingdang_service', dingdang_processor)# 单线程服务器server = TServer.TSimpleServer(multi_processor, transport, tfactory, pfactory)print("Starting python server...")server.serve()print("done!")


9. 编写客户端文件client.py

#!/usr/bin/python# -*- coding:utf-8 -*-from thrift import Thriftfrom thrift.protocol.TMultiplexedProtocol import TMultiplexedProtocolfrom thrift.transport import TSocketfrom thrift.transport import TTransportfrom thrift.protocol import TBinaryProtocolfrom thrift.protocol import TCompactProtocolfrom gen.pingpong import PingPong, DingDangdef ping_client():    try:        # common        tsocket = TSocket.TSocket('127.0.0.1', 8080)  # 通信socket并设置请求ip和端口        transport = TTransport.TBufferedTransport(tsocket)  # 传输类型        # single service        protocol = TBinaryProtocol.TBinaryProtocol(transport)  # 通信协议二进制协议(与服务器端保持一致)        # protocol = TCompactProtocol.TCompactProtocol(transport)        # multi service 多服务        pingpong_service = TMultiplexedProtocol(protocol, 'pingpong_service![这里写图片描述](http://img.blog.csdn.net/20170414232117718?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvanc2OTAxMTQ1NDk=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)')        dingdang_service = TMultiplexedProtocol(protocol, 'dingdang_service')        pingpong_client = PingPong.Client(pingpong_service)        dingdang_client = DingDang.Client(dingdang_service)        transport.open()  # 打开socket传输并建立连接        print("The return value is : ")        print(pingpong_client.ping())        print(dingdang_client.ding())        print("............")        transport.close()    except Thrift.TException as tx:        print('%s' % tx.message)if __name__ == '__main__':    ping_client()


10. 分别执行server.py和client.py,得到返回结果。
客户端:

The return value is : pong............

服务器:

Starting python server...192.168.1.136

最简单的demo到此结束。很快会想到两个问题(已更新)。
问题一:各行代码的简单含义?
问题二:是否同一端口(socket)能监听多个服务?(利用TMultiplexedProcessorTMultiplexedProtocol

thrift IDL

文档
参考: Thrift 使用方法
由浅入深了解Thrift(一)——Thrift介绍与用法

对照该博客的建议写了一些枚举和自定义数据结构的返回类型,但总感觉用起来很繁琐。

认为值得注意的点:
1. 指定namespace: namespace py user_service使生成的目录在user_service模块下,可是实际生成不在项目根目录下,出现引用错误,只能添加了sys.path.append('gen')生成的文件
test_server.py
是否有其他好的解决办法?
2. 枚举无序号;自定义结构体有序号;方法参数有序号。

service UserService {    th_datatype.ResultString getName(1:string user_id)    th_datatype.ResultInt getAge(1:string user_id)}

3.自定义结构体的成员默认optional(必须是required)。

struct ResultBool{    1: ThriftResult result,    2: bool value,}

4.枚举默认从0开始,可以指定默认值(16位整数)。

enum ThriftResult {    SUCCESS = 1000,    EXCEPTION = 1001,}

5.支持list,map,set。
6. 利用inclue导入其他thrift文件,将数据类型和服务分开定义。

include "th_datatype.thrift"

th_user.thrift

/* 定义接口函数 */namespace py user_service/* 导入数据类型 */include "th_datatype.thrift"service UserService {    th_datatype.ResultString getName(1:string user_id)    th_datatype.ResultInt getAge(1:string user_id)}

th_datatype.thrift

/* 定义返回值类型 */namespace py datatypeconst string VERSION = "1.0.1"/* 枚举无序号 */enum ThriftResult {    SUCCESS = 1000,    EXCEPTION = 1001,}/* 自定义结构体有序号 */struct ResultBool{    1: ThriftResult result,    2: bool value,}struct ResultInt {    1: ThriftResult result,    2: i32 value,}struct ResultLong {    1: ThriftResult result,    2: i64 value,}struct ResultDouble {    1: ThriftResult result,    2: double value,}struct ResultString {    1: ThriftResult result,    2: string value,}struct ResultListString {    1: ThriftResult result,    2: list<string> value,}struct ResultSetString {    1: ThriftResult result,    2: set<string> value,}struct ResultMapStrStr {    1: ThriftResult result,    2: map<string, string> value,}

test_server.py

#!/usr/bin/python# -*- coding:utf-8 -*-import syssys.path.append('gen')from thrift.transport import TSocketfrom thrift.transport import TTransportfrom thrift.protocol import TBinaryProtocolfrom thrift.server import TServerfrom user_service import UserServicefrom datatype.ttypes import ThriftResult, ResultInt, ResultStringimport socketclass UserServiceHandler(object):    def getName(self, user_id):        host = socket.gethostbyname(socket.gethostname())        print('host: %s, user_id: %s' % (host, user_id))        return ResultString(ThriftResult.SUCCESS, 'JiangW')    def getAge(self, user_id):        host = socket.gethostbyname(socket.gethostname())        print('host: %s, user_id: %s' % (host, user_id))        return ResultInt(ThriftResult.SUCCESS, 23)handler = UserServiceHandler()# 注册实现类processor = UserService.Processor(handler)transport = TSocket.TServerSocket('127.0.0.1', 8080)tfactory = TTransport.TBufferedTransportFactory()pfactory = TBinaryProtocol.TBinaryProtocolFactory()server = TServer.TSimpleServer(processor, transport, tfactory, pfactory)print("Starting python server...")server.serve()print("done!")

test_client.py

#!/usr/bin/python# -*- coding:utf-8 -*-import syssys.path.append('gen')from thrift import Thriftfrom thrift.transport import TSocketfrom thrift.transport import TTransportfrom thrift.protocol import TBinaryProtocolfrom user_service import UserServicedef client_execute():    try:        transport = TSocket.TSocket('127.0.0.1', 8080)        transport = TTransport.TBufferedTransport(transport)        protocol = TBinaryProtocol.TBinaryProtocol(transport)        client = UserService.Client(protocol)        transport.open()        res_name = client.getName('1')        print("user name %s." % res_name.result)        res_age = client.getAge('1')        print("user age %s." % res_age.result)        print("user name: %s, age %s." % (res_name.value, res_age.value))        print("............")        transport.close()    except Thrift.TException as tx:        print('%s' % tx.message)if __name__ == '__main__':    client_execute()
0 0
原创粉丝点击