Fork me on GitHub

Thrift 学习笔记:RPC Server 和 Client

在了解 Thrift IDL 后,就能开始编写自己的 RPC 服务端和客户端了。对 Thrift 的安装过程和命令操作略过不表,主要还是关注如何利用 Thrift 实现 Java 的 RPC 服务端和客户端。

服务接口描述

首先需要定义服务接口描述,即 .thrift 文件,再由 Thrift 将接口描述文件编译成相应的客户端和服务端的 stub 代码。

官网 Tutorial 给出的示例略复杂,不妨自己写一个简单的 Hello World 文件:

1
2
3
4
5
6
7
8
9
// tutorial.thrift
namespace java com.isudox.thrift.tutorial
typedef i32 int
service CustomService {
int add(1:int a, 2:int b)
string sayHello(1:string name)
}

描述文件写的很简单,只定义了一个接口,包含两个函数。将 tutorial.thrift 编译成 Java 代码:

1
thrift -r --gen java tutorial.thrift

生成如下 Java 文件:

1
2
3
4
5
6
gen-java
└── com
└── isudox
└── thrift
└── tutorial
└── CustomService.java

下面是 CustomService.java 的部分代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
package com.isudox.thrift.tutorial;
@SuppressWarnings({"cast", "rawtypes", "serial", "unchecked", "unused"})
@javax.annotation.Generated(value = "Autogenerated by Thrift Compiler (0.10.0)", date = "2017-04-10")
public class CustomService {
public interface Iface {
public int add(int a, int b) throws org.apache.thrift.TException;
public java.lang.String sayHello(java.lang.String name) throws org.apache.thrift.TException;
}
// 后面省略...
}

可以看到,Thrift 自动生成了接口 CustomService.Iface,包含 add() 和 sayHello() 函数。

另外,如果是 Maven 构建的项目,在模块的 pom.xml 文件中添加 Thrift 依赖:

1
2
3
4
5
<dependency>
<groupId>org.apache.thrift</groupId>
<artifactId>libthrift</artifactId>
<version>0.10.0</version>
</dependency>

有了上面的编译后的 stub 代码,就能对 RPC 服务端和客户端具体实现进行编码了。

Server & Client

在编写 RPC Server 和 Client 代码前,得先把 Thrift 定义的接口实现。编写 CustomServiceHandler.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// CustomServiceHandler.java
package com.isudox.thrift.tutorial
import org.apache.thrift.*
public class CustomServiceHandler implements CustomService.Iface {
@Override
public int add(int a, int b) throws TException {
return a + b;
}
@Override
public String sayHello(String name) throws TException {
return "Hello " + name;
}
}

然后就能编写 Server 和 Client 的具体实现了,通过 CustomServiceHandler 来实现远程调用;

CustomServer.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
// CustomServer.java
package com.isudox.thrift.tutorial
import org.apache.thrift.*
public class CustomServer {
public static CustomServiceHandler handler;
public static CustomService.Processor processor;
public static void main(String[] args) {
try {
handler = new CustomServiceHandler();
processor = new CustomService.Processor(handler);
Runnable simple = new Runnable() {
public void run() {
simple(processor);
}
};
new Thread(simple).start();
} catch (Exception e) {
e.printStackTrace();
}
}
public static void simple(CustomService.Processor<CustomServiceHandler> processor) {
try {
TServerTransport st = new TServerSocket(9090);
TServer server = new TSimpleServer(new Args(st).processor(processor));
System.out.println("Starting the simple server...");
server.serve();
}
catch (Exception e) {
e.printStackTrace();
}
}
}

CustomClient.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
// CustomClient.java
package com.isudox.thrift.tutorial
import org.apache.thrift.*
public class CustomClient {
public static void main(String[] args) {
try {
TTransport transport = new TSocket("localhost", 9090);
transport.open();
TProtocol protocol = new TBinaryProtocol(transport); // 二进制格式
CustomService.Client client = new CustomService.Client(protocol);
System.out.print(client.add(1, 2));
System.out.print(client.sayHello("sudoz"));
transport.close();
} catch (TTransportException te) {
te.printStackTrace();
} catch (TException e) {
e.printStackTrace();
}
}
}

运行 Server 端 main 函数,会以 simple 的模式启动,然后运行 Client,可以看到输出了 Thrift 定义的接口的函数运行结果。


参考资料: