Thrift是一个软件框架,用来进行可扩展且跨语言的服务的开发。它结合了功能强大的软件堆栈和代码生成引擎,以构建在 C++, Java, Go,Python, PHP, Ruby, Erlang, Perl, Haskell, C#, Cocoa, JavaScript, Node.js, Smalltalk, and OCaml 这些编程语言间无缝结合的、高效的服务。Thrift最初由facebook开发,07年四月开放源码,08年5月进入apache孵化器。thrift允许你定义一个简单的定义文件中的数据类型和服务接口。以作为输入文件,编译器生成代码用来方便地生成RPC客户端和服务器通信的无缝跨编程语言。
本文主要介绍 Thrift 开发流程,并给出 C++,Java,C#,Python 和 Go开发 Thrfit 应用的实例。
本文的开发环境为: WIN10
Thrift用接口描述语言(Interface description language,IDL)来描述不同编程语言之间的接口。Thrift开发环境包含两个部分:Thrift编译器和语言相关的库。Thrift编译器用来根据IDL生成语言相关的接口代码框架,我们可以使用这个框架很方便的实现客户端和服务器的代码。语言相关的库则封装了不同编程语言之间通信的内部实现,让我们解放双手着重处理业务逻辑。根据编程语言的不同,构建相关库的方法也不同。
语言相关的库代码在Thrift源代码的lib下,每种语言一个目录,比如C++就在cpp目录下。在每种语言的目录下,都有一个README.md用来描述该语言库的构建和使用方法。语言相关的库根据编程语言的不同,构建的方式也不同。如果是编译型语言的话,则需要编译。
本例的编译环境为: WIN10 + VS2015
C++库的源码包含在 lib/cpp 中,在该目录中可以看到两个工程,一个是 libthrift,另一个是 libthriftnb。其中libthriftnb 是非阻塞版本(nb 表示 nonblocking)。这两个工程依赖三个库:BOOST,OpenSSL 和 libevent,因此首先编译这三个库。
下载 BOOST库,本例下载的版本为 1.64.0。下载后解压到合适的目录。由于 Thrift 使用了 BOOST 中的 thread 库,因此需要编译BOOST。
打开VS2015开发人员命令提示符,切换到 [BOOST解压目录],执行以下命令建立编译环境:
bootstrap.bat
执行以下命令编译。其中 --toolset
指定了编译工具,由于本例用 VS2015 编译,因此指定为 msvc-14.0
。--stagedir
指定了生成库的存放路径。
bjam stage --toolset=msvc-14.0 --without-graph_parallel --stagedir="G:\libs\boost_1_64_0\bin\vc14" link=static runtime-link=shared runtime-link=static threading=multi debug release
喝咖啡。
下载并安装 Perl,本例下载的版本是:strawberry-perl-5.26.0.1-64bit.msi 。安装后确认 [Perl安装目录]\perl\bin 目录是否在环境变量中,如果不在则手动添加。
下载并安装 NASM,本例下载的版本是:nasm-2.13.01-installer-x64.exe 。安装后将 [NASM安装目录] 添加到环境变量中。
下载 OpenSSL 源码并解压,本例下载的版本为:openssl-1.0.1e.tar.gz
打开VS2015开发人员命令提示符,切换到 [OpenSSL解压目录],执行以下命令进行配置,其中--openssldir
指定安装目录,VC-WIN32
表示编译成32位的库,如果想要生成64位则改为VC-WIN64A
:
perl Configure --openssldir=G:\libs\openssl-1.0.1e VC-WIN32
执行以下命令生成MakeFile:
ms\do_ms
执行以下命令编译动态库,如果要编译静态库,则将ntdll.mak换成nt.mak:
nmake -f ms\ntdll.mak
执行以下命令进行安装,安装后会在--openssldir
指定的目录中找到编译好的库:
nmake -f ms\ntdll.mak install
在libevent官网下载 libevent 源代码并解压,本例下载的版本为:libevent-2.0.22-stable.tar.gz
打开 VS2015 开发人员命令提示符,切换到解压目录,执行以下命令进行编译:
nmake Makefile.nmake
编译好了依赖库,就可以编译Thrift库了。
进入 [Thrift源码]\lib\cpp 目录,用 VS2015 打开 thrift.sln,如果提示升级编译器和库,则进行升级。
切换到解决方案页签,展开libthrift工程,server 目录右键 -> 添加 -> 现有项,将 [Thrift源代码目录]\lib\cpp\src\thrift\server\ 目录下的以下四个文件加入到工程中(如果已经在工程中则忽略):
"TServerFramework.cpp"
"TServerFramework.h"
"TConnectedClient.cpp"
"TConnectedClient.h"
主菜单中 视图 -> 其他窗口 -> 属性管理器
双击 3rdparty ,选择 User Macros,将BOOST_ROOT、OPENSSL_ROOT_DIR、 LIBEVENT_ROOT 改成自己的目录。
切换到解决方案页签,编译 libthrift 和 libthriftnb。编译成功后生成libthrift.lib 和 libthriftnb.lib。这两个库就是在开发时所依赖的库。
##构建Java库
本例构建环境:
java version "1.8.0_131"
Apache Ant(TM) version 1.10.1
在编译之前请确保正确安装和配置了 JDK 和 Ant。
Java库源代码目录为:[Thrift源代码目录]\lib\java。Java库需要使用Ant 来编译。管理员方式打开命令行,切换到Java库元源代码目录,执行:
ant
编译后会在 build 子目录下找到 libthrift-0.10.0.jar,这就是我们需要的开发包。在 build/lib 下是 libthrift-0.10.0.jar 的依赖包。
要求 .NET framework >= 3.5
本例的编译环境为: WIN10 + VS2015
C#库的存放目录为:[Thrift源代码目录]\lib\csharp\src,打开Thrift.sln,编译Thrift项目,编译成功后得到 Thrift.dll。
本例的Python版本为:Python 3.5.3
安装 Python 可以通过源代码中的安装脚本来安装,也可以使用 Python 包管理工具 pip 来安装。
###通过安装脚本安装
Python的库在 [Thrift源代码目录]\lib\py 目录中,该目录中可以找到 setup.py 安装脚本。利用该脚本可以很方便的安装 Python 库。
以管理员权限打开命令行,切换到 Python 库目录。
执行以下命令编译Python库。编译后库会生成在当前目录下的build子目录中。
setup.py build
执行以下命令安装Python库。安装后会在 [Python安装目录]\Lib\site-packages 下生成需要的库: thrift-0.10.0-py3.5-win-amd64.egg 。
setup.py install
也可以通过 Python 包管理工具 pip 来安装:
pip install thrift
本例的环境为:WIN10 + go1.8.1 windows/amd64
推荐使用 go get 下载最新的 Thrift 库。首先在环境变量里设置好GOPATH,如下图所示。GOPATH的值根据自己的实际情况设置即可。设置好GOPATH之后,使用 go get 工具下载的包就会放在该目录下。
以管理员权限打开命令提示符(不必切换目录)。利用 go get 下载 Thrift 库,命令如下。下载完毕后就会在 GOPATH 指定的目录找到 Go 的 Thrift 库。
go get git.apache.org/thrift.git/lib/go/thrift/...
Thrift 中 IDL 文件以 .thrift 为后缀。该文件用来描述服务器与客户端之间的接口。在编写 thrift 文件之前,还需要了解一下用以描述接口的语法。
##注释
Thrift 支持三种注释:
脚本注释,用 #
表示,例如:
# 这是一个注释
块注释,用 /*
和 */
表示。
/*
* 这是一个注释
*/
单行注释,用 //
表示。
// 这是一个注释
类型 | 描述 |
---|---|
bool |
布尔类型,1byte |
i8 |
有符号整形,8bits,即byte |
i16 |
有符号整型,16bits |
i32 |
有符号整型,32bits |
i64 |
有符号整型,64bits |
double |
浮点型,64bits |
string |
字符串 |
binary |
Blob,byte数组 |
map |
map |
list |
有序列表 |
set |
无重复元素的容器 |
常量用const表示:
const i32 MATHPATH = 256
用 enum 定义枚举。枚举类型是32位的整数。值是可选的,从1开始。
enum Operation {
ADD = 1,
SUBTRACT = 2,
MULTIPLY = 3,
DIVIDE = 4
}
结构体用 struct 表示,是基本的复合数据类型,由若干字段组成。每个字段由整型ID,类型,名称和可选的默认值组成。字段可以声明为 optional,表示如果没有被设置,则不进行序列化。
struct Work {
1: i32 num1 = 0,
2: i32 num2,
3: Operation op,
4: optional string comment,
}
结构体也可以定义为异常:
exception InvalidOperation {
1: i32 whatOp,
2: string why
}
服务类似 class, 用 service 关键字定义。服务可以用 extends 关键字继承其他服务。service 由一系列方法组成。方法由返回值,参数列表和一个可选的异常列表组成。参数列表和异常列表的语法和结构体的语法一样。
service Calculator extends shared.SharedService {
void ping(),
i32 add(1:i32 num1, 2:i32 num2),
i32 calculate(1:i32 logid, 2:Work w) throws (1:InvalidOperation ouch),
/**
* oneway 表示客户端发送请求后不需要响应。onway 方法返回值必须是void
*/
oneway void zip()
}
用 include 指令包含其他 thrift 文件:
include "another.thrift"
namespace 指令指定语言相关的名称空间:
namespace cpp nscpp # 指定C++的名称空间为 nscpp
namespace java nsjava # 指定Java的包为 nsjava
typedef 指令用来指定类型别名,和 C 一样。
typedef i32 MyInteger
Thrift 编译器的用法如下:
thrift [options] file
可以通过 --help 选项来了解具体用法:
thrift --help
通常用以下命令将IDL编译成语言相关的接口代码,-r
(recurse的首字母)表示递归生成被包含的文件,--gen
后面接生成的语言。
thrift-0.10.0.exe -r --gen cpp ICalc.thrift
下面分别给出 C++、JAVA、C#,Python 和 Go 开发 Thrift 应用的实例。需要注意的是某种语言开发的服务器和任何语言开发的客户端都可以实现互联,这正是 Thrift 的特性之一。
本例环境:WIN10 + VS2015
在开发之前应确保 C++ 的 Thrift 库已经编译好,如果还没有编译好,请参见构建C++库。
新建空白解决方案,命名为 Calc,点击确定。如下图所示:
I C a l c . t h r i f t ‾ \underline{ICalc.thrift} ICalc.thrift
service ICalc {
i32 add(1:i32 num1, 2:i32 num2),
}
ICalc.thrift 右键,在弹出菜单中选择属性,如下图所示:
ICalc.cpp
ICalc.h
ICalc_constants.cpp
ICalc_constants.h
ICalc_server.skeleton.cpp
ICalc_types.cpp
ICalc_types.h
解决方案右键,[添加] -> [新建项目],如下图所示:
I C a l c _ s e r v e r . s k e l e t o n . c p p ‾ \underline{ICalc\_server.skeleton.cpp} ICalc_server.skeleton.cpp
int32_t add(const int32_t num1, const int32_t num2) {
return num1 + num2;
}
Ctrl + A, Ctrl + K, Ctrl + F 格式化代码。
编译工程,生成Server.exe。
在 [OpenSSL目录]\bin 下找到 libeay32.dll
和 ssleay32.dll
,将这两个 DLL 复制到 Server.exe 同目录下。
解决方案右键,在弹出菜单中选择 [添加] -> [新建项目],如下图所示:
m a i n . c p p ‾ \underline{main.cpp} main.cpp
#include
#include
#include
#include
#include "ICalc.h"
using namespace std;
using namespace apache::thrift;
using namespace apache::thrift::protocol;
using namespace apache::thrift::transport;
int main()
{
boost::shared_ptr socket(new TSocket("localhost", 9090));
boost::shared_ptr transport(new TBufferedTransport(socket));
boost::shared_ptr protocol(new TBinaryProtocol(transport));
ICalcClient client(protocol);
try
{
transport->open();
int32_t sum = client.add(1, 2);
std::cout << sum << std::endl;
transport->close();
}
catch (TException& tx)
{
cout << "ERROR: " << tx.what() << endl;
}
system("pause");
return 0;
}
[工程属性] -> [配置属性] -> [C/C++] -> [常规] -> [附加包含目录],添加 boost 库目录,C++ 的 Thrift 目录以及 Thrift编译器生成的接口的目录。如下图所示:
在 [OpenSSL目录]\bin 下找到 libeay32.dll
和 ssleay32.dll
,将这两个 DLL 复制到 Client.exe 同目录下。
运行 Server.exe,再运行 Client.exe,会在 Client.exe 窗口打印 3,如下图所示:
本例开发环境:
java version "1.8.0_131"
Apache Ant(TM) version 1.10.1
在开发之前应确保 Java 的 Thrift 包已经编译好,如果还没有编译好,请参见构建Java库。
首先建立如下所示的目录结构。其中 com/cynhard/thrift/test
是包的路径,可以根据自己的域名进行调整。iface
, server
, client
三个目录分别用来存放接口,服务器,客户端的代码。build.xml
是Ant构建文件。
[somewhere]
|-calc/
|-com/
| |-cynhard/
| |-thrift/
| |-test/
| |-iface/ -- 接口文件目录
| | |-ICalc.thrift -- 接口文件
| |-server/ -- 服务器目录
| | |-Server.java -- 服务器实现文件
| |-client/ -- 客户端目录
| |-Client.java -- 客户端实现文件
|-build.xml -- ant 文件
###定义接口
打开 ICalc.thrift 文件,编写接口代码如下。注意包名应该根据自己的实际路径调整。
I C a l c . t h r i f t ‾ \underline{ICalc.thrift } ICalc.thrift
namespace java com.cynhard.thrift.test.iface
service ICalc {
i32 add(1:i32 num1, 2:i32 num2),
}
打开 Server.java,编写服务器代码如下。注意包名应该根据自己的实际路径调整。
S e r v e r . j a v a ‾ \underline{Server.java} Server.java
package com.cynhard.thrift.test.server;
import org.apache.thrift.TException;
import org.apache.thrift.server.TServer;
import org.apache.thrift.server.TServer.Args;
import org.apache.thrift.server.TSimpleServer;
import org.apache.thrift.transport.TServerSocket;
import org.apache.thrift.transport.TServerTransport;
import com.cynhard.thrift.test.iface.ICalc;
public class Server {
static class CalcHandler implements ICalc.Iface {
@Override
public int add(int num1, int num2) throws TException {
return num1 + num2;
}
}
public static void main(String[] args) {
try {
CalcHandler handler = new CalcHandler();
ICalc.Processor processor = new ICalc.Processor(handler);
TServerTransport serverTransport = new TServerSocket(9090);
TServer server = new TSimpleServer(new Args(serverTransport).processor(processor));
System.out.println("Starting the server...");
server.serve();
} catch (Exception e) {
e.printStackTrace();
}
}
}
打开 Client.java,编写客户端代码如下。注意包名应该根据自己的实际路径调整。
C l i e n t . j a v a ‾ \underline{Client.java} Client.java
package com.cynhard.thrift.test.client;
import org.apache.thrift.TException;
import org.apache.thrift.transport.TTransport;
import org.apache.thrift.transport.TSocket;
import org.apache.thrift.protocol.TBinaryProtocol;
import org.apache.thrift.protocol.TProtocol;
import com.cynhard.thrift.test.iface.ICalc;
public class Client {
public static void main(String[] args) {
try {
TTransport transport = new TSocket("localhost", 9090);
transport.open();
TProtocol protocol = new TBinaryProtocol(transport);
ICalc.Client client = new ICalc.Client(protocol);
System.out.println(client.add(1, 2));
transport.close();
} catch (TException e) {
e.printStackTrace();
}
}
}
打开 build.xml,编写构建配置如下。注意路径属性需要根据实际路径进行修改。
b u i l d . x m l ‾ \underline{build.xml} build.xml
<project name="calc" basedir="." default="build">
<property name="thrift.lib.dir" value="G:\libs\thrift-0.10.0\lib\java\build"/>
<property name="thrift.compiler.dir" value="G:\tools\thrift"/>
<property name="interface.dir" value="${basedir}\com\cynhard\thrift\test\iface"/>
<path id="master-classpath">
<fileset dir="${thrift.lib.dir}">
<include name="**\*.jar"/>
fileset>
<pathelement path="."/>
path>
<target name="build" description="Compile Calc">
<exec executable="${thrift.compiler.dir}\thrift-0.10.0.exe">
<arg line="--gen java -out ${basedir} ${interface.dir}\ICalc.thrift"/>
exec>
<javac>
<src path="."/>
<classpath refid="master-classpath"/>
javac>
target>
<target name="run_server" description="Run server">
<java fork="true" failonerror="yes" classname="com.cynhard.thrift.test.server.Server">
<classpath refid="master-classpath"/>
java>
target>
<target name="run_client" description="Run client">
<java fork="true" failonerror="yes" classname="com.cynhard.thrift.test.client.Client">
<classpath refid="master-classpath"/>
java>
target>
project>
上面的工作完成后,就可以开始构建工程了。以管理员权限打开命令提示符,切换到 calc 目录。执行以下命令编译工程:
ant build
编译成功后,服务器和客户端相应的class文件就生成在了相应的目录中。下面就可以开始测试了。
执行以下命令运行服务器。
ant run_server
输出结果如下,可以看到输出了 Starting the server...
,表明服务器已经启动。
Buildfile: G:\projects\java\calc\build.xml
run_server:
[java] Starting the server...
因为服务器在一个单独的窗口运行,为了测试客户端,需要打开另一个命令提示符,同样切换到 calc 目录。执行以下命令运行客户端:
ant run_client
输出结果如下,可以看到返回了正确的结果:3 。
Buildfile: G:\projects\java\calc\build.xml
run_client:
[java] Received 1
[java] 3
BUILD SUCCESSFUL
Total time: 0 seconds
本例环境:WIN10 + VS2015
在开发之前应确保 C# 的 Thrift 库已经编译好,如果还没有编译好,请参见构建C#库。
新建空白解决方案,命名为 Calc,点击确定。如下图所示:
I C a l c . t h r i f t ‾ \underline{ICalc.thrift} ICalc.thrift
service ICalc {
i32 add(1:i32 num1, 2:i32 num2),
}
ICalc.thrift 右键,在弹出菜单中选择属性,如下图所示:
[解决方案]右键,在弹出菜单中选择 [添加] -> [新建项目],如下图所示:
P r o g r a m . c s ‾ \underline{Program.cs} Program.cs
using System;
using Thrift.Server;
using Thrift.Transport;
namespace Server
{
class CalcHandler : ICalc.Iface
{
public int add(int num1, int num2)
{
return num1 + num2;
}
}
class Program
{
static void Main(string[] args)
{
try
{
CalcHandler handler = new CalcHandler();
ICalc.Processor processor = new ICalc.Processor(handler);
TServerTransport serverTransport = new TServerSocket(9090);
TServer server = new TSimpleServer(processor, serverTransport);
// Use this for a multithreaded server
// server = new TThreadPoolServer(processor, serverTransport);
Console.WriteLine("Starting the server...");
server.Serve();
}
catch (Exception x)
{
Console.WriteLine(x.StackTrace);
}
Console.WriteLine("done.");
}
}
}
编译工程,生成Server.exe。
[解决方案]右键,在弹出菜单中选择 [添加] -> [新建项目],如下图所示:
P r o g r a m . c s ‾ \underline{Program.cs} Program.cs
using System;
using Thrift;
using Thrift.Transport;
using Thrift.Protocol;
namespace Client
{
class Program
{
static void Main(string[] args)
{
try
{
TTransport transport = new TSocket("localhost", 9090);
TProtocol protocol = new TBinaryProtocol(transport);
ICalc.Client client = new ICalc.Client(protocol);
transport.Open();
try
{
int sum = client.add(1, 2);
Console.WriteLine(sum);
}
finally
{
transport.Close();
}
}
catch (TApplicationException x)
{
Console.WriteLine(x.StackTrace);
}
}
}
}
编译工程,生成 Client.exe。
运行 Server.exe,再运行 Client.exe,会在 Client.exe 窗口打印 3,如下图所示:
本例的Python版本为:Python 3.5.3
在开发之前应确保 Python 的 Thrift 包已经安装好,如果还没有安装好,请参见构建Python库。
首先建立如下所示的目录结构。
[somewhere]
|-calc/
|-ICalc.thrift -- 接口文件
|-Server.py -- 服务器实现文件
|-Client.py -- 客户端实现文件
###定义接口
打开 ICalc.thrift,编写代码如下,注意这里定义了模块名为 calc。
I C a l c . t h r i f t ‾ \underline{ICalc.thrift} ICalc.thrift
namespace py calc
service ICalc {
i32 add(1:i32 num1, 2:i32 num2),
}
以管理员权限打开命令提示符,切换到 calc 目录,执行如下命令生成接口代码。注意因为 Python 包名不能带连字符(-
),但是默认生成的文件夹中间是带连字符的(比如gen-py
), 因此这里用了 -out
选项指定输出目录。
mkdir genpy
thrift-0.10.0.exe --gen py -out genpy ICalc.thrift
打开 Server.py,编写如下代码:
S e r v e r . p y ‾ \underline{Server.py} Server.py
''' Server '''
from thrift.transport import TSocket
from thrift.transport import TTransport
from thrift.protocol import TBinaryProtocol
from thrift.server import TServer
from genpy.calc.ICalc import Processor
class CalcHandler:
''' CalcHandler '''
def add(self, num1, num2):
''' add '''
return num1 + num2
if __name__ == '__main__':
HANDLER = CalcHandler()
PROCESSOR = Processor(HANDLER)
TRANSPORT = TSocket.TServerSocket('0.0.0.0', port=9090)
TFACTORY = TTransport.TBufferedTransportFactory()
PFACTORY = TBinaryProtocol.TBinaryProtocolFactory()
SERVER = TServer.TSimpleServer(PROCESSOR, TRANSPORT, TFACTORY, PFACTORY)
print('Starting the server...')
SERVER.serve()
print('done.')
###实现客户端
打开 Client.py,编写如下代码:
C l i e n t . p y ‾ \underline{Client.py} Client.py
''' Client '''
from thrift.Thrift import TException
from thrift.transport import TSocket
from thrift.transport import TTransport
from thrift.protocol import TBinaryProtocol
from genpy.calc.ICalc import Client
if __name__ == '__main__':
try:
# Make socket
TRANSPORT = TSocket.TSocket('localhost', 9090)
# Buffering is critical. Raw sockets are very slow
TRANSPORT = TTransport.TBufferedTransport(TRANSPORT)
# Wrap in a protocol
PROTOCOL = TBinaryProtocol.TBinaryProtocol(TRANSPORT)
# Create a client to use the protocol encoder
CLIENT = Client(PROTOCOL)
# Connect!
TRANSPORT.open()
print(str(CLIENT.add(1, 2)))
# Close!
TRANSPORT.close()
except TException as exceptioin:
print('%s', exceptioin.message)
首先运行服务器。以管理员身份运行命令提示符,切换到 calc 目录,执行如下命令启动服务器:
python Server.py
运行客户端。以管理员身份运行命令提示符,切换到 calc 目录,执行如下命令启动客户端:
python Client.py
执行结果输出:3
。
本例的环境为:WIN10 + go1.8.1 windows/amd64
Go的主要环境变量为:
GOARCH=amd64
GOPATH=G:\projects\go
GOROOT=G:\Go
在开发之前应确保 Go 的 Thrift 包已经安装好,如果还没有安装好,请参见构建Go库。
首先建立如下的目录结构。其中的 cynhard.com/tests/thrfit
可以根据实际情况修改。
[GOPATH]/src/
|-cynhard.com/
|-tests/
|-thrift/
|-iface/
| |-ICalc.thrift -- 接口文件
|-server/
| |-Server.go -- 服务器实现文件
|-client/
|-Client.go -- 客户端实现文件
打开 ICalc.thrift ,编写如下代码。按照Go的习惯,这里将包名定义为 iface,与目录名保持一致。
I C a l c . t h r i f t ‾ \underline{ICalc.thrift} ICalc.thrift
namespace go iface
service ICalc {
i32 add(1:i32 num1, 2:i32 num2),
}
以管理员权限打开命令提示符,切换到 iface 目录,执行以下命令生成接口代码。注意这里用 -out
选项指定生成目录为上级目录,Thrift 编译器在生成代码时,发现上级目录存在 iface 子目录,就把生成的文件放到该目录下。这正是我们想要的目录结构。
thrift-0.10.0.exe --gen go -out .. ICalc.thrift
打开 Server.go,编写如下代码:
S e r v e r . g o ‾ \underline{Server.go} Server.go
package main
import (
"log"
"cynhard.com/tests/thrift/iface"
"git.apache.org/thrift.git/lib/go/thrift"
)
type calcHandler struct{}
func (handler calcHandler) Add(num1 int32, num2 int32) (r int32, err error) {
r = num1 + num2
err = nil
return
}
func main() {
processor := iface.NewICalcProcessor(calcHandler{})
transport, err := thrift.NewTServerSocket("localhost:9090")
if err != nil {
log.Fatalf("%s\n", err.Error())
}
server := thrift.NewTSimpleServer2(processor, transport)
server.Serve()
}
打开 Client.go,编写如下代码:
C l i e n t . g o ‾ \underline{Client.go} Client.go
package main
import (
"fmt"
"log"
"cynhard.com/tests/thrift/iface"
"git.apache.org/thrift.git/lib/go/thrift"
)
func main() {
transport, err := thrift.NewTSocket("localhost:9090")
if err != nil {
log.Fatalf("%s\n", err.Error())
}
protocolFactory := thrift.NewTBinaryProtocolFactoryDefault()
client := iface.NewICalcClientFactory(transport, protocolFactory)
transport.Open()
defer transport.Close()
sum, err := client.Add(1, 2)
if err != nil {
log.Fatalf("%s\n", err.Error())
}
fmt.Printf("%d", sum)
}
以管理员权限打开命令提示符,切换到 server 目录下,执行以下命令启动服务器:
go run Server.go
以管理员权限打开命令提示符,切换到 client 目录下,执行以下命令启动客户端:
go run Client.go
可以看到输出结果为:3
。