一。thrift 0.9.0的版本的例子编译cpp有好多问题,特此记录一下
1. 在tutorial/cpp下直接make,出现一堆错误,随便截取一下
”/usr/local/include/thrift/protocol/TProtocol.h:312: error: ‘uint32_t’ does not name a type“还有什么ntohl找不到什么的,是由于MakeFile中没有指定
-DHAVE_NETINET_IN_H,导致没有包含#include <arpa/inet.h>头文件
2. 添加-DHAVE_NETINET_IN_H后,出现
/usr/local/include/thrift/concurrency/Thread.h:90: error: ‘pthread_self’ was not declared in this scope等等pthread的函数找不到定义,是没有包含pthread.h头文件
在MakeFile中添加 -DHAVE_PTHREAD_H
3. 编译成功后运行出现
error ' error while loading shared libraries: libthrift-0.9.0.so: cannot open shared object file: No such file or directory'
说找不到libthrift动态链接库,但是在/usr/local/lib下确实存在,还需要在自己的.bashrc问价中添加
export LD_LIBRARY_PATH=/usr/local/lib
然后source .bashrc
终于运行成功。。。
二。对tutorial例子的简单解析
由于tutorial中的例子存在.thrift文件的相互依赖,因此在首先对thrift文件进行编译时,需要首先编译
thrift -gen cpp shared.thrift
shared.thrift内容如下
struct SharedStruct { 1: i32 key 2: string value}service SharedService { SharedStruct getStruct(1: i32 key)}
此时在gen-cpp目录下生成了
shared_constants.cpp
shared_constants.h
SharedService.cpp
SharedService.h
SharedService_server.skeleton.cpp
shared_types.cpp
shared_types.h
其中*_constants.*文件保存了在thrift文件中定义的常量信息,*_types.*文件保存了thrift文件中定义的类型信息,上述信息供我们编写server和client业务逻辑时参考。
而*Service.*文件,定义了Service的对外接口。skeleton文件则是thrift为我们生成的桩文件,当我们开发Server时,直接将该文件cp到编码的文件夹下添加业务逻辑(实现Service文件中的接口即可)。
然后在 thrift -gen cpp tutorial.thrift
此时可以看到
Calculator.cpp
Calculator.h
Calculator_server.skeleton.cpp
三个文件(忽视掉之前生成的文件以及 constants和types文件),这三个文件中 Calculator.*文件已经帮我们写好了大量的rpc操作,我们此时只需要在skeleton文件中将Calculator.h中定义的但未在Calculator.cpp中实现的接口实现,就好了。(实际上thrift都已经把框架搭建好了,我们只需要修改skeleton文件,实现业务逻辑的接口就好)
仔细对照gen-cpp/下的skeleton文件和cpp/下的CppServer.cpp文件就可以发现,CppServer.cpp不仅仅实现了skeleton文件中的接口,还另外实现了
void getStruct(SharedStruct &ret, const int32_t logid) {
printf("getStruct(%d)\n", logid);
ret = log[logid];
}
这是因为在tutorial.thrift文件中include了shared.thrift文件,且继承了shared.SharedService,因此生成的Calculator.h中,我们就看到
class CalculatorIf : virtual public ::shared::SharedServiceIf
也就是说这个CalculatorIf接口还继承了SharedServiceIf接口,所以实现该接口的类必须要将所有继承的接口全部实现,而getStruct接口就是SharedServiceIf的唯一接口,所以才有了CppServer的实现。
另外,对于Service服务,thrift会直接帮我们生成skeleton文件,简化编码,但是对于client则不行,我们可以把cpp/下的CppClient.cpp文件作为自己的一个模板文件,简化代码编写工作
#include <stdio.h>
#include <unistd.h>
#include <sys/time.h>
#include <thrift/protocol/TBinaryProtocol.h>
#include <thrift/transport/TSocket.h>
#include <thrift/transport/TTransportUtils.h>
#include "../gen-cpp/Calculator.h"
using namespace std;
using namespace apache::thrift;
using namespace apache::thrift::protocol;
using namespace apache::thrift::transport;
using namespace tutorial;
using namespace shared;
using namespace boost;
int main(int argc, char** argv) {
shared_ptr<TTransport> socket(new TSocket("localhost", 9090));
shared_ptr<TTransport> transport(new TBufferedTransport(socket));
shared_ptr<TProtocol> protocol(new TBinaryProtocol(transport));
CalculatorClient client(protocol);
try {
transport->open();
/* ToDo
client.ping();
printf("ping()\n");
int32_t sum = client.add(1,1);
printf("1+1=%d\n", sum);
Work work;
work.op = Operation::DIVIDE;
work.num1 = 1;
work.num2 = 0;
try {
int32_t quotient = client.calculate(1, work);
printf("Whoa? We can divide by zero!\n");
} catch (InvalidOperation &io) {
printf("InvalidOperation: %s\n", io.why.c_str());
}
work.op = Operation::SUBTRACT;
work.num1 = 15;
work.num2 = 10;
int32_t diff = client.calculate(1, work);
printf("15-10=%d\n", diff);
// Note that C++ uses return by reference for complex types to avoid
// costly copy construction
SharedStruct ss;
client.getStruct(ss, 1);
printf("Check log: %s\n", ss.value.c_str());
end of ToDo */
transport->close();
} catch (TException &tx) {
printf("ERROR: %s\n", tx.what());
}
}