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文件和目标语言来为其生成代码。 示例如下:
每一步的解释如下:
#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。
示例如下:
步骤解析如下:
#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 sys
sys.path.append("gen-py")
以这种方式将gen-py目录添加到路径是比较快速简便的,适合于开发和测试。如果从gen-py的父目录之外的其他位置运行示例,则需要在此处提供完整路径。在生产环境中,您可能会将生成的Python软件包安装在Python路径上已经存在的目录中,例如“ site-packages”目录,从而无需此代码。
下一步是导入一些Thrift模块。
from thrift.transport import TSocket
from 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()
在命令行运行情况如下:
服务器启动来等待客户端请求。
今天就看到这里,欢迎关注交流~