您的位置:首页 > 编程语言 > C语言/C++

Thrift C++ 服务器和客户端开发实例--学习笔记

2017-04-13 18:39 537 查看
C++服务器和客户端开发

参考:thrift下C++服务器和客户端开发

参考:ThriftUsageC++

参考:Thrift 入门教程

Thrift环境搭建:

Ubuntu环境下Thrift的安装、编译以及测试

ubuntu下thrift的安装

RPC框架之Thrift分析

1 实现这个例子,我们大致要做以下几部分事情:

(1)书写.thrift文件

(2)生成cpp文件

(3)编写客户端

(4)编译cpp文件并执行

下面是详细的步骤:

(1)书写.thrift文件

学生信息是有结构的,所以我们使用thrift的struct即可,为了达到通信的目的,我们必须使用service。

所以最后书写成的student.thrift文件内容如下:

struct Student{
1: i32 sno,
2: string sname,
3: bool ssex,
4: i16 sage,
}

service Serv{
void put(1: Student s),
i32 icall(1: Student s),
string scall(1: Student s),
/*
string& srcall(1: Student s),
-----------------------------
-thrift -r --gen cpp student.thrift
-error:
-   [ERROR:/root/test/thrift/student.thrift:12] (last token was '&')
-   syntax error
-   [FAILURE:/root/test/thrift/student.thrift:12] Parser error during include pass.
-----------------------------
*/
Student stcall(1: Student s),
}


(2)生成cpp文件

生成cpp文件很简单,只需要一个thrift命令即可:

/home/xiaoshe/opt/bin/thrift -r –gen cpp student.thrift

–gen 后指定生成的语言,生成的cpp存储在目录gen-cpp下

命令执行后,将会在./gen-cpp/目录下生成如下文件:

Serv.cpp

Serv.h

Serv_server.skeleton.cpp

student_constants.cpp

student_constants.h

student_types.cpp

student_types.h

注意文件的大小写:

Serv开头的文件是由service生成的,这个关键字很重要,下面还会见到以它开头的类。

student是根据student.thrift文件的名生成的。

这些文件可以进行编译,生成最初的服务端。

(3)编写客户端

使用thrift命令后,我们并没有得到我们想要的客户端client源代码,因此客户端程序要由我们自己编写实现。Client代码如下:

#include "Serv.h"
#include <transport/TSocket.h>
#include <transport/TBufferTransports.h>
#include <protocol/TBinaryProtocol.h>

using namespace apache::thrift;
using namespace apache::thrift::protocol;
using namespace apache::thrift::transport;

using boost::shared_ptr;

int main(int argc, char **argv)
{
boost::shared_ptr<TSocket> socket(new TSocket("localhost", 9090));
boost::shared_ptr<TTransport> transport(new TBufferedTransport(socket));
boost::shared_ptr<TProtocol> protocol(new TBinaryProtocol(transport));

transport->open();

//调用server服务
Student s;
s.sno = 123;
s.sname = "hao973";
s.ssex = 1;
s.sage = 30;

ServClient client(protocol);
printf("sno=%d sname=%s ssex=%d sage=%d\n", s.sno, s.sname.c_str(), s.ssex, s.sage);
//put
client.put(s);
//icall scall
std::string strname = "";
client.scall(strname, s);
printf("icall=%d, scall=%s\n", client.icall(s), strname.c_str());
//stcall
client.stcall(stu, s);
printf("student sno=%d sname=%s ssex=%d sage=%d\n", stu.sno, stu.sname.c_str(), stu.ssex, stu.sage);

transport->close();

return 0;
}


同时修改服务端的代码及文件Serv_server.skeleton.cpp中:

在Serv_server.skeleton.cpp文件中put函数中添加:

//add by self

printf(“sno=%d sname=%s ssex=%d sage=%d\n”, s.sno, s.sname.c_str(), s.ssex, s.sage);

// This autogenerated skeleton file illustrates how to build a server.
// You should copy it to another filename to avoid overwriting it.

#include "Serv.h"
#include <thrift/protocol/TBinaryProtocol.h>
#include <thrift/server/TSimpleServer.h>
#include <thrift/transport/TServerSocket.h>
#include <thrift/transport/TBufferTransports.h>

using namespace ::apache::thrift;
using namespace ::apache::thrift::protocol;
using namespace ::apache::thrift::transport;
using namespace ::apache::thrift::server;

using boost::shared_ptr;

class ServHandler : virtual public ServIf {
public:
ServHandler() {
// Your initialization goes here
}

void put(const Student& s) {
// Your
4000
implementation goes here
printf("put\n");
printf("sno=%d sname=%s ssex=%d sage=%d\n", s.sno, s.sname.c_str(), s.ssex, s.sage);
}

int32_t icall(const Student& s) {
// Your implementation goes here
printf("icall\n");
printf("sno=%d sname=%s ssex=%d sage=%d\n", s.sno, s.sname.c_str(), s.ssex, s.sage);
return s.sage;
}

void scall(std::string& _return, const Student& s) {
// Your implementation goes here
printf("scall\n");
printf("sno=%d sname=%s ssex=%d sage=%d\n", s.sno, s.sname.c_str(), s.ssex, s.sage);
_return = s.sname;
}

void stcall(Student& stu, const Student& s) {
// Your implementation goes here
printf("stcall\n");
printf("sno=%d sname=%s ssex=%d sage=%d\n", s.sno, s.sname.c_str(), s.ssex, s.sage);
stu.sno     = s.sno + 1;
stu.sname   = s.sname + "123";
stu.ssex    = s.ssex;
stu.sage    = s.sage + 10;
}

};

int main(int argc, char **argv) {
int port = 9090;
shared_ptr<ServHandler> handler(new ServHandler());
shared_ptr<TProcessor> processor(new ServProcessor(handler));
shared_ptr<TServerTransport> serverTransport(new TServerSocket(port));
shared_ptr<TTransportFactory> transportFactory(new TBufferedTransportFactory());
shared_ptr<TProtocolFactory> protocolFactory(new TBinaryProtocolFactory());

TSimpleServer server(processor, serverTransport, transportFactory, protocolFactory);
server.serve();
return 0;
}


2 编译链接:

编译程序命令:

//服务器

g++ -g -Wall -I./ -I/usr/local/include/thrift Serv.cpp student_types.cpp student_constants.cpp Serv_server.skeleton.cpp -L/usr/local/lib/*.so -lthrift -o server

//客户端

g++ -g -Wall -I./ -I/usr/local/include/thrift Serv.cpp student_types.cpp student_constants.cpp Client.cpp -L/usr/local/lib/*.so -lthrift -o client

注意:

在自己的环境下要是把-L/usr/local/lib/.so -lthrift

放在 .cpp 和 .o文件前面会出现链接错误。部分错误如下:

/tmp/ccvtijvB.o:在函数‘ServClient::recv_put()’中:

/root/test/thrift/gen-cpp/Serv.cpp:197:对‘apache::thrift::TApplicationException::read(apache::thrift::protocol::TProtocol*)’未定义的引用

/tmp/ccvtijvB.o:在函数‘ServProcessor::dispatchCall(apache::thrift::protocol::TProtocol*, apache::thrift::protocol::TProtocol*, std::__cxx11::basic_string

CC=g++ -g -Wall

CFLAGS = -I. -I/usr/local/include/thrift

LFLAGS = -L/usr/local/lib

LDEXEFLAGS = -lthrift

OBJS = Serv.o \
student_types.o \
student_constants.o

all:client server

Serv.o: Serv.cpp
$(CC) $(CFLAGS) -c $^ -o $@
student_types.o: student_types.cpp
$(CC) $(CFLAGS) -c $^ -o $@
student_constants.o: student_constants.cpp
$(CC) $(CFLAGS) -c $^ -o $@
Serv_server.skeleton.o: Serv_server.skeleton.cpp
$(CC) $(CFLAGS) -c $^ -o $@
Client.o: Client.cpp
$(CC) $(CFLAGS) -c $^ -o $@

server: $(OBJS) Serv_server.skeleton.o
$(CC) $(LFLAGS) $(OBJS) Serv_server.skeleton.o  $(LDEXEFLAGS) -o $@

client: $(OBJS)  Client.o
$(CC) $(LFLAGS) $(OBJS)  Client.o  $(LDEXEFLAGS) -o $@

clean:
rm -f ./*.o client server


3 运行结果:

先启动server.

再运行client.

server输出:

# ./server
put
sno=123 sname=hao973 ssex=1 sage=30
scall
sno=123 sname=hao973 ssex=1 sage=30
icall
sno=123 sname=hao973 ssex=1 sage=30
stcall
sno=123 sname=hao973 ssex=1 sage=30


client执行结果:

# ./client
sno=123 sname=hao973 ssex=1 sage=30
icall=30, scall=hao973
student sno=124 sname=hao973123 ssex=1 sage=40
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  thrift C++