简单学习rpc -- thrift demos

本文详细介绍Thrift RPC框架的使用方法,包括环境搭建、服务端与客户端的开发流程,并通过示例代码展示了如何实现多服务监听及自定义数据结构。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

简单介绍:
  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 Thrift
from thrift.TMultiplexedProcessor import TMultiplexedProcessor
from thrift.transport import TSocket
from thrift.transport import TTransport
from thrift.protocol import TBinaryProtocol
from thrift.protocol import TCompactProtocol
from thrift.server import TServer
from gen.pingpong import PingPong, DingDang

import socket


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


# common
transport = TSocket.TServerSocket('127.0.0.1', 8080)  # 通信socket并设置服务端口
tfactory = TTransport.TBufferedTransportFactory()  # 传输工厂类
pfactory = TBinaryProtocol.TBinaryProtocolFactory()  # 二进制协议工厂类
# pfactory = TCompactProtocol.TCompactProtocolFactory()

# processors
pingpong_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 Thrift
from thrift.protocol.TMultiplexedProtocol import TMultiplexedProtocol
from thrift.transport import TSocket
from thrift.transport import TTransport
from thrift.protocol import TBinaryProtocol
from thrift.protocol import TCompactProtocol

from gen.pingpong import PingPong, DingDang


def 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![这里写图片描述](https://img-blog.youkuaiyun.com/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 datatype

const 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 sys
sys.path.append('gen')

from thrift.transport import TSocket
from thrift.transport import TTransport
from thrift.protocol import TBinaryProtocol
from thrift.server import TServer
from user_service import UserService
from datatype.ttypes import ThriftResult, ResultInt, ResultString

import socket


class 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 sys
sys.path.append('gen')

from thrift import Thrift
from thrift.transport import TSocket
from thrift.transport import TTransport
from thrift.protocol import TBinaryProtocol
from user_service import UserService


def 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()
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值