vlambda博客
学习文章列表

Thrift—构建一个RPC实例(一)

1. Apache Thrift IDL

    服务在接口定义语言(IDL)文件中定义。 服务接口是客户端和服务器之间通信的基础。Thrift IDL文件只是用Apache Thrift IDL编码的纯文本文件,并具有“ .thrift”扩展名。

    以下是一个IDL文件的例子:

service HelloSvc { #A string hello_func() #B}

    该IDL文件声明了一个称为HelloSvc 的服务接口。HelloSvc有一个函数hello_func(),该函数不接受任何参数并返回字符串类型。

    为了将此接口转换为有用的代码,我们可以使用Apache Thrift IDL编译器对其进行编译。Apache Thrift编译器二进制文件在UNIX(如系统)上被称为“ thrift”,在Windows上被称为“ thrift.exe”。要运行编译器,需要向其传递IDL文件和目标语言来为其生成代码。 示例如下:

Thrift—构建一个RPC实例(一)

    每一步的解释如下:

#A 在命令行上调用Apache Thrift编译器,使用IDL文件进行编译,并使用“ -gen”开关指定要输出的语言,在这种情况下为Python#B 编译器为Python源文件创建一个“ gen-py”输出目录。#C 输出目录包含一个与IDL文件同名的Python包。#D constants.py文件包含IDL中的常量定义。#E 编译器为IDL中定义的每个服务创建一个Python模块。#F 编译器的Python生成器为每个服务创建一个Python测试客户端。#G Python使用__init__.py文件将目录指定为Python#H ttypes.py文件包含源IDL中的用户定义类型。


2. 构建python服务端

    注:目前文章中Apache Thrift的代码不支持Python3.x。构建Python示例

需要Python 2.5 –2.7.x。

    示例如下:

Thrift—构建一个RPC实例(一)

        步骤解析如下:

#A 在这里,我们将生成的代码的位置添加到Python路径中,以便import语句可以找到它#B 我们将使用Apache Thrift TCP / IP套接字模块公开我们的服务#C 所有服务器执行逻辑将由内置的Apache Thrift Server驱动#D IDL编译器生成的HelloSvc模块提供了我们所有应用程序特定的RPC代码#E HelloHandler类是我们实现服务的地方#F 编译器生成的服务处理器将客户端请求分派给我们的处理程序#G 我们的监听套接字将使用端口8585#H 服务器serve()方法运行服务器

    下面来逐行分析代码的实用。用Python编写Apache Thrift应用程序时,我们面临的第一个配置问题是Python在Python路径上的当前目录和目录中搜索要导入的软件包。IDL编译器生成的hello包位于gen-py目录下。为简单起见,我们导入标准的python sys模块,并将“ gen-py”附加到Python路径,以便我们可以直接从hello包中导入元素。

import syssys.path.append("gen-py")

    以这种方式将gen-py目录添加到路径是比较快速简便的,适合于开发和测试。如果从gen-py的父目录之外的其他位置运行示例,则需要在此处提供完整路径。在生产环境中,您可能会将生成的Python软件包安装在Python路径上已经存在的目录中,例如“ site-packages”目录,从而无需此代码。

    下一步是导入一些Thrift模块。

from thrift.transport import TSocketfrom thrift.server import TServer

    Thrift库分为子包/目录。在这种情况下,我们从服务器包中导入服务器模块,从传输包中导入套接字模块。这将使我们能够使用TCP / IP套接字创建基本的RPC服务器进行通信。

     为我们的服务生成的IDL编译器存根代码放在与该服务同名的python文件中,并在与IDL文件同名的包中。我们将使用Thrift生成的服务器存根(在Apache Thrift中称为“处理器”)来调度来自客户端的服务调用。

       下面的代码从hello包中导入我们的服务模块HelloSvc.py。

from hello import HelloSvc

     现在,我们可以为HelloSvc服务实现处理程序。它实际上提供了服务方法的行为。处理程序“处理”来自客户端的RPC调用。

class HelloHandler: def hello_func(self): print("[Server] Handling client request")    return "Hello thrift, from the python server"

    所有Service方法都必须在Handler类中表示,在这个例子中,是hello_func()方法。

    现在,我们可以构造并连接实现服务器所需的所有对象。

handler = HelloHandler()processor = HelloSvc.Processor(handler)listening_socket = TSocket.TServerSocket(port=8585)server = TServer.TSimpleServer(processor, listening_socket)

    首先,我们创建处理程序的实例,然后将处理程序包装在由IDL编译器为我们生成的HelloSvc处理器中。处理器处理来自网络的调用,并调用正确的处理程序方法。接下来的TSocket模块TServerSocket类是用于监听端口8585上的连接。

    最后一部分是构造一个对象,以将所有这些功能组织到可运行的服务器中。 服务器必须使用侦听套接字来处理客户端连接,并在客户端请求进入时调用处理器。标准的TServer模块包含一个TSimpleServer类,它为我们解决了这一问题。TSimpleServer类具有一个运行服务器的关键方法serve()。

print ("[Server] Started")server.serve()

    在命令行运行情况如下:

    服务器启动来等待客户端请求。


    今天就看到这里,欢迎关注交流~