用户工具


创建thrift文件

按thrift语法格式编写一个文件,这个文件定义了RPC的接口和数据类型

Hello.thrift

           
 namespace java service.demo 
 service Hello{ 
  string helloString(1:string para) 
  i32 helloInt(1:i32 para) 
  bool helloBoolean(1:bool para) 
  void helloVoid() 
  string helloNull() 
 } 

其中定义了服务叫 Hello, 有五个方法,每个方法包含一个方法名,参数列表和返回类型。每个参数包括参数序号,参数类型以及参数名。 Thrift 是对 IDL(Interface Definition Language) 描述性语言的一种具体实现。因此,以上的服务描述文件使用 IDL 语法编写。使用 Thrift 工具编译 Hello.thrift,就会生成相应的 Hello.java 文件。该文件包含了在 Hello.thrift 文件中描述的服务 Hello 的接口定义,即 Hello.Iface 接口(server端需要实现的接口),以及服务调用的底层通信细节,包括客户端的调用逻辑 Hello.Client (client端需要实现的接口)以及服务器端的处理逻辑 Hello.Processor,用于构建客户端和服务器端的功能。

生成java语言的rpc框架

thrift -r –gen java Hello.thrift

这时候会生成一个Hello.java的源文件。这个文件就包含了rpc框架的实现(server端,client端都需要用到这个文件)

服务端实现

将上一步生成的Hello.java拷贝到当前项目中

创建 HelloServiceImpl.java 文件并实现 Hello.java 文件中的 Hello.Iface 接口

HelloServiceImpl.java

package service.demo; 
 import org.apache.thrift.TException; 
 public class HelloServiceImpl implements Hello.Iface { 
    @Override 
    public boolean helloBoolean(boolean para) throws TException { 
        return para; 
    } 
    @Override 
    public int helloInt(int para) throws TException { 
        try { 
            Thread.sleep(20000); 
        } catch (InterruptedException e) { 
            e.printStackTrace(); 
        } 
        return para; 
    } 
    @Override 
    public String helloNull() throws TException { 
        return null; 
    } 
    @Override 
    public String helloString(String para) throws TException { 
        System.out.println("recv: "+ para);
        return "return: "+ para; 
    } 
    @Override 
    public void helloVoid() throws TException { 
        System.out.println("Hello World"); 
    } 
 } 

创建服务器端实现代码,将 HelloServiceImpl 作为具体的处理器传递给 Thrift 服务器

HelloServiceServer.java

package service.server; 
 import org.apache.thrift.TProcessor; 
 import org.apache.thrift.protocol.TBinaryProtocol; 
 import org.apache.thrift.protocol.TBinaryProtocol.Factory; 
 import org.apache.thrift.server.TServer; 
 import org.apache.thrift.server.TThreadPoolServer; 
 import org.apache.thrift.transport.TServerSocket; 
 import org.apache.thrift.transport.TTransportException; 
 import service.demo.Hello; 
 import service.demo.HelloServiceImpl; 

 public class HelloServiceServer { 
    /** 
     * 启动 Thrift 服务器
     * @param args 
     */ 
    public static void main(String[] args) { 
        try { 
            // 设置服务端口为 7911 
            TServerSocket serverTransport = new TServerSocket(7911); 
            // 设置协议工厂为 TBinaryProtocol.Factory 
            Factory proFactory = new TBinaryProtocol.Factory(); 
            // 关联处理器与 Hello 服务的实现
            TProcessor processor = new Hello.Processor(new HelloServiceImpl()); 
            //TServer server = new TThreadPoolServer(processor, serverTransport, 
                    proFactory); 
            TServer server = new TThreadPoolServer(new TThreadPoolServer.Args(serverTransport).processor(processor));
            System.out.println("Start server on port 7911..."); 
            server.serve(); 
        } catch (TTransportException e) { 
            e.printStackTrace(); 
        } 
    } 
 } 

maven配置

    <dependencies>
        <dependency>
            <groupId>org.apache.thrift</groupId>
            <artifactId>libthrift</artifactId>
            <version>0.9.2</version>
        </dependency>
        
        # 官方只给了上面一个配置,结果运行错误,网上搜的答复是再添加下面这个配置(错误解决)
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-api</artifactId>
            <version>1.7.6</version>
            <scope>compile</scope>
            <optional>true</optional>
        </dependency>

客户端实现(java)

将上一步生成的Hello.java拷贝到当前项目中

创建客户端实现代码,调用 Hello.client 访问服务端的逻辑实现

HelloServiceClient.java

package service.client; 
 import org.apache.thrift.TException; 
 import org.apache.thrift.protocol.TBinaryProtocol; 
 import org.apache.thrift.protocol.TProtocol; 
 import org.apache.thrift.transport.TSocket; 
 import org.apache.thrift.transport.TTransport; 
 import org.apache.thrift.transport.TTransportException; 
 import service.demo.Hello; 

 public class HelloServiceClient { 
 /** 
     * 调用 Hello 服务
     * @param args 
     */ 
    public static void main(String[] args) { 
        try { 
            // 设置调用的服务地址为本地,端口为 7911 
            TTransport transport = new TSocket("localhost", 7911); 
            transport.open(); 
            // 设置传输协议为 TBinaryProtocol 
            TProtocol protocol = new TBinaryProtocol(transport); 
            Hello.Client client = new Hello.Client(protocol); 
            // 调用服务的 helloVoid 方法
            System.out.println(client.helloVoid()); 
            transport.close(); 
        } catch (TTransportException e) { 
            e.printStackTrace(); 
        } catch (TException e) { 
            e.printStackTrace(); 
        } 
    } 
 } 

客户端实现(python)

初始化环境

# 安装thrift依赖的库
sudo easy_install pip
sudo pip install thrift

修改Hello.thrift文件 (将javas 改成 py)

 namespace py service.demo 
 service Hello{ 
  string helloString(1:string para) 
  i32 helloInt(1:i32 para) 
  bool helloBoolean(1:bool para) 
  void helloVoid() 
  string helloNull() 
 } 

生成python的rpc框架

thrift -r –gen py Hello.thrift

命令执行之后会生成Hello.py和一些其他文件。 我在当前目录下新建一个fang.py,代码如下

我为了方便测试,直接在当前目录下创建了fang.py。如果Python项目放在其他路径,一定要保证Hello.py及其依赖的文件都能被import进来

import sys

from Hello import Client
from thrift import Thrift
from thrift.transport import TSocket
from thrift.transport import TTransport
from thrift.protocol import TBinaryProtocol
from thrift.protocol import TCompactProtocol

def run():
    try:
        transport = TSocket.TSocket('master', 7911)
        transport = TTransport.TBufferedTransport(transport)
        protocol = TBinaryProtocol.TBinaryProtocol(transport)
        # 一定要保证和服务器端的协议相同
        #protocol = TCompactProtocol.TCompactProtocol(transport)
        client = Client(protocol)
        transport.open()
        print client.helloString("python")
        transport.close()
    except Thrift.TException, tx:
        print '%s' % (tx.message)

if __name__ == '__main__':
    run()

client端发送的协议一定要和server端接收的协议相同