vieyahn2017 / thrift-trial

my thrift trial.
0 stars 0 forks source link

样例(cpp版本) #4

Open vieyahn2017 opened 5 years ago

vieyahn2017 commented 5 years ago

cpp版本稍微复杂些 make比较麻烦

vieyahn2017 commented 5 years ago

例子来自333m

Thrift简介、安装与简单使用

1.简介 Thrift是一个跨语言的服务部署框架,最初由Facebook于2007年开发,2008年进入Apache开源项目。Thrift通过一个中间语言(IDL, 接口定义语言)来定义RPC的接口和数据类型,然后通过一个编译器生成不同语言的代码(目前支持C++,Java,Python, PHP, Ruby, Erlang, Perl, Haskell, C#, Cocoa, Smalltalk和OCaml),并由生成的代码负责RPC协议层和传输层的实现。类似的框架有googleprotocol,avro,message pack等。

2.架构

Thrift实际上是实现了C/S模式,通过代码生成工具将接口定义文件(*.thrift)生成服务器端和客户端代码(可以为不同语言),从而实现服务端和客户端跨语言的支持。用户在Thirft描述文件中声明自己的服务,这些服务经过编译后会生成相应语言的代码文件,然后用户实现服务(客户端调用服务,服务器端提服务)便可以了。其中protocol(协议层, 定义数据传输格式,可以为二进制或者XML等)和transport(传输层,定义数据传输方式,可以为TCP/IP传输,内存共享或者文件共享等)被用作运行时库。

3.支持的RPC与序列化格式与类型 数据类型

TCompactProtocol – 压缩格式

TJSONProtocol – JSON格式

TSimpleJSONProtocol –提供JSON只写协议, 生成的文件很容易通过脚本语言解析。

TDebugProtocol – 使用易懂的可读的文本格式,以便于debug12

3.12支持的数据传输方式 TFramedTransport – 以frame为单位进行传输,非阻塞式服务中使用。

TFileTransport – 以文件形式进行传输。

TMemoryTransport – 将内存用于I/O.java实现时内部实际使用了简单的ByteArrayOutputStream。

TZlibTransport – 使用zlib进行压缩, 与其他传输方式联合使用。当前无java实现。

3.13支持的服务模型

TSocket -阻塞式socker(一般用于客户端)

TSimpleServer – 简单的单线程服务模型,常用于测试

TThreadPoolServer – 多线程服务模型,使用标准的阻塞式IO。

TNonblockingServer – 单线程服务模型,使用非阻塞式IO(需使用TFramedTransport数据传输方式)

TThreadedServer - 多线程服务模型,使用阻塞式IO,每个请求创建一个线程。 TThreadPoolServer – 线程池服务模型,使用标准的阻塞式IO,预先创建一组线程处理请求。 TNonblockingServer – 多线程服务模型,使用非阻塞式IO(需使用TFramedTransport数据传输方式)(C++服务)

THsHaServer - 多线程 non blocking的服务(java服务)

处理大量更新的话,主要是在TThreadedServer和TNonblockingServer中进行选择。TNonblockingServer能够使用少量线程处理大量并发连接,但是延迟较高;TThreadedServer的延迟较低。实际中,TThreadedServer的吞吐量可能会比TNonblockingServer高,但是TThreadedServer的CPU占用要比TNonblockingServer高很多。

3.2Thrift支持的类型 Thrift支持的类型系统包括预定义基本类型,用户自定义结构体,容器类型,异常和服务定义。

3.21基本类型 bool:布尔类型(true or value),占一个字节

byte:有符号字节

i16: 16位有符号整型

i32: 32位有符号整型

i64: 64位有符号整型

double:64位浮点数

string:未知编码或者二进制的字符串

*注意,thrift不支持无符号整型,因为很多目标语言不存在无符号整型(如java)。

还有枚举和常量。

3.22容器类型 Thrift容器与类型密切相关,它与当前流行编程语言提供的容器类型相对应,采用java泛型风格表示的。Thrift提供了3种容器类型:

List:一系列t1类型的元素组成的有序表,元素可以重复

Set:一系列t1类型的元素组成的无序表,元素唯一

Map<t1,t2>:key/value对(key的类型是t1且key唯一,value类型是t2)。

容器中的元素类型可以是除了service以外的任何合法thrift类型(包括结构体和异常)。

3.23结构体、异常和服务 在面向对象语言中,thrift结构体被转换成类。它在语义上不同于结构体—当定义一个RPC服务时,开发者可能需要声明一个远程方法抛出一个异常。服务的定义方法在语法上等同于面向对象语言中定义接口。Thrift编译器会产生实现这些接口的client和server桩。

4.Thrift安装 Thrift涉及到网络和支持的多语言(可以选择性安装)。另外在支持Cpp语言时,可以使用boost库来作为Thrift作为它的底层库;支持java时要安装JDK和ant。另外还需要ssl服务。

4.1 openssl安装 因为thrift依赖于ssl服务所以先安装ssl.

  1. 官网下载ssl。

  2. 解压:tar xvf openssl-1.0.0g.tar.gz

  3. 配置编译动态库和支持64位 ./config -shared –fPIC

  4. Make --》 make install

4.2 boost安装 参考程实blog:http://hi3ms.huawei.com/hi/group/4931/blog_149169.html

4.3 libevent安装 我安装的是1.4左右的稳定版本,主要是为了TNonblockingServer模式。

./configure ——》 make ——》 make install

4.4 安装Thrift

  1. 官网下载thrift。

  2. 解压:tar xvf 0.8

  3. 配置编译库./configure --with-boost=/usr/local LDFLAGS="-L/usr/local/ssl/lib" CPPFLAGS="-I/usr/local/ssl/include"

LDFLAGS找不到库的时候添加库路径 ,CPPFLAGS找不到头文件路径的时候添加头文件路径

  1. Make --》 make install

出现:/usr/include/c++/4.3/cstdlib:124: error: '::malloc' has not been declared等错误的话:可以把config.h的 把#define malloc rpl_malloc注释掉(先重新configure ,再修改,再编译。。。)。

参考:http://hi.baidu.com/paopao_312/blog/item/9ed388ceda1f563eb700c86a.html

*注意make失败时,可能是头文件和库文件找不到,可以添加以下两个变量:

LD_LIBRARY_PATH:库文件

C_INCLUDE_PATH: (for C header files)

CPLUS_INCLUDE_PATH: (for C++ header files)

vieyahn2017 commented 5 years ago

5.Thrift简单使用

编写一个简单的demo,实现客户端与服务端的helloworld和结构体(类)传输,对于java也类似。

5.1定义*.thrift文件

namespace cpp demo    //支持cpp,并定义空间;
namespace java demo   //支持java;
//定义结构体,在支持面向对象的语言(如cpp、java)为类。
struct Student{
         1:i32 sno,
         2:string sname,
         3:bool ssex, 
         4:i16 sage, 
}  

//定义方法
service Serv{ 
         Student put(1: Student s),
         string hello_word(1:string para)
}

5.2生成代码文件 生成cpp代码:

thrift -r --gen cpp student.thrift

如果是要生成java代码:

thrift -r --gen java student.thrift

其他语言类似。

生成的代码在./gen-cpp目录下

其中server端代码入口为:

Serv_server.skeleton.cpp

5.3编写客户端代码 //client.cpp

#include "Serv.h"  // Your .h File 
#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; 
using namespace demo; 

void print_st(Student& s){
 printf("num is: %d \n",s.sno);
 printf("name is: %s \n",s.sname.c_str());
  if(true ==s.ssex){
   printf("sex is: man! \n");
  }else{
   printf("sex is: woman! \n");
  }
 printf("age is: %d \n",s.sage);
};

int main() { 
boost::shared_ptr<TSocket> socket(newTSocket("localhost", 9090)); 

boost::shared_ptr<TTransport> transport(newTBufferedTransport(socket)); 
boost::shared_ptr<TProtocol> protocol(newTBinaryProtocol(transport)); 

ServClient client(protocol);
try{ 
   transport->open(); 

    //发送和接收stu对象并打印
    Studentst;
   st.__set_sno(222);
   st.__set_sname("shuishuijiang");
    Studentst_b;
   print_st(st);
   client.put(st_b,st);
    print_st(st_b);

    //helloworld!
   std::string send = "hello server!";
   std::string rec ;
   client.hello_word(rec,send);
   printf("Server say: %s\n", rec.c_str());
    //关闭接口
   transport->close(); 
}catch(TException &tx){
   printf("ERROR: %s\n", tx.what());
} 
return 1; 
}

5.4修改服务端代码 //Serv_server.skeleton.cpp

// This autogenerated skeleton file illustrates howto build a server.

#include "Serv.h"
#include <protocol/TBinaryProtocol.h>
#include <server/TSimpleServer.h>
#include <transport/TServerSocket.h>
#include <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;
using namespace ::demo;

void print_st(const Student& s){ 
   printf("num is: %d \n",s.sno); 
   printf("name is: %s \n",s.sname.c_str()); 
    if(true ==s.ssex){   
       printf("sex is: man! \n"); 
    }else{
       printf("sex is: woman! \n");
    }   
   printf("age is: %d \n",s.sage);
}

class ServHandler : virtual public ServIf{
 public:
 ServHandler() {
   // Your initialization goes here
   printf("Initializated!\n");
  }

 void put(Student& _return, const Student& s) {
   // Your implementation goes here
   printf("recived!\n");   
   print_st(s);   
   _return.__set_sname("shuishuihaoren");
   _return.__set_ssex(true);
   //add over!
   printf("send!\n");
  }

 void hello_word(std::string& _return, const std::string& para) {
   // Your implementation goes here
         //要发送给的client的string;
   _return = "Hi, client!";
   //add over
   printf("client say: %s\n",para.c_str());
  }
};

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(newTServerSocket(port));
 shared_ptr<TTransportFactory> transportFactory(newTBufferedTransportFactory());
 shared_ptr<TProtocolFactory> protocolFactory(new TBinaryProtocolFactory());
 TSimpleServer server(processor, serverTransport, transportFactory,protocolFactory);
 server.serve();
  return 0;
}

5.5编译、运行 用cmake来编译的:CMakeList.txt如下:

#CMake脚本的执行方法:1)cd build 2)cmake .. 3)make
#如果需要生成windows下的程序,第一步变为cmake -G,例如使用MinGW编译为:cmake -G “MinGW Makefiles”
cmake_minimum_required(VERSION 2.8)
PROJECT(demo_thrift)

#可执行文件生成在bin目录下
SET(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin)
#库代码添加到此处
AUX_SOURCE_DIRECTORY(./gen-cpp/ DIR_SRCS)
#compileto lib
ADD_LIBRARY(demo_lib ${DIR_SRCS}  )

#编译选项(Debug or Release)
SET(CMAKE_CXX_FLAGS_DEBUG "$ENV{CXXFLAGS} -O0 -Wall -g -ggdb -lthriftnb -lthrift -lthriftnb -levent -lpthread")
SET(CMAKE_CXX_FLAGS_RELEASE "$ENV{CXXFLAGS} -O3 -Wall -lthriftnb -lthrift -lthriftnb -levent -lpthread")
#SET(CMAKE_BUILD_TYPE Release)
SET(CMAKE_BUILD_TYPE Debug)
#解决uint_32等类型编译不过的错误
SET(CMAKE_CXX_FLAGS "-DHAVE_NETINET_IN_H -DHAVE_INTTYPES_H")

SET(THRIFT_INCLUDE_PATH "/usr/local/include/thrift" )
SET(THRIFT_LIBRARY_PATH "/usr/local/lib" )
INCLUDE_DIRECTORIES(${THRIFT_INCLUDE_PATH})
LINK_DIRECTORIES(${THRIFT_LIBRARY_PATH})

#可执行代码添加到此处(main函数入口)
ADD_EXECUTABLE(client gen-cpp/client.cpp)             #clent
         TARGET_LINK_LIBRARIES( client demo_lib"thrift" )
ADD_EXECUTABLE(server gen-cpp/Serv_server.skeleton.cpp)          #clent
         TARGET_LINK_LIBRARIES( server demo_lib"thrift" )

创建外部编译目录:

mkdir build || rm -rf build/* && cd build && cmake .. && make all

运行服务端和客户端

./build/bin/server
./build/bin/client

kill服务端

pgrep -f server |xargs kill -9
vieyahn2017 commented 5 years ago

使用CMakeList.txt报错

文件目录

CMakeLists.txt  gen-cpp  student.thrift

gen-cpp文件夹:

Serv.cpp Serv.h  Serv_server.skeleton.cpp  student_constants.cpp  student_constants.h  student_types.cpp  student_types.h

新建build文件夹后, 到build目录执行:

cmake ..

-- The C compiler identification is GNU 4.8.5
-- The CXX compiler identification is GNU 4.8.5
-- Check for working C compiler: /bin/cc
-- Check for working C compiler: /bin/cc -- works
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Check for working CXX compiler: /bin/c++
-- Check for working CXX compiler: /bin/c++ -- works
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Configuring done
-- Generating done
-- Build files have been written to: /usr/local/thrift-0.10.0/yh/build

make all

Scanning dependencies of target demo_lib
[ 20%] Building CXX object CMakeFiles/demo_lib.dir/gen-cpp/student_types.cpp.o
[ 40%] Building CXX object CMakeFiles/demo_lib.dir/gen-cpp/student_constants.cpp.o
[ 60%] Building CXX object CMakeFiles/demo_lib.dir/gen-cpp/Serv.cpp.o
[ 80%] Building CXX object CMakeFiles/demo_lib.dir/gen-cpp/Serv_server.skeleton.cpp.o
Linking CXX static library libdemo_lib.a
[ 80%] Built target demo_lib
Scanning dependencies of target server
[100%] Building CXX object CMakeFiles/server.dir/gen-cpp/Serv_server.skeleton.cpp.o
Linking CXX executable bin/server
/bin/ld: cannot find -lthriftnb
/bin/ld: cannot find -lthriftnb
/bin/ld: cannot find -levent
collect2: error: ld returned 1 exit status
make[2]: *** [bin/server] Error 1
make[1]: *** [CMakeFiles/server.dir/all] Error 2
make: *** [all] Error 2
vieyahn2017 commented 5 years ago

搜了一个帖子说:

关于编译安装Thrift找不到libthriftnb.a的问题

https://www.cnblogs.com/caosiyang/archive/2012/09/29/2708867.html

Thrift 服务端有如下模式:TSimpleServer TThreadpoolServer TThreadedServer TNonblockingServer

NonblockingServer是非阻塞的,编写非阻塞服务端程序需要链接库libthriftnb.a,即 -lthriftnb

如果找不到libthriftnb.a,可能是以下问题:

1.之前没有安装libevent,解决方法是安装libevent,再重新编译安装Thrift

2.安装libevent,没有生成libevent动态库

最初遇到这个问题是因为未安装libevent,但是安装libevent重新编译Thrfit仍然没有thriftnb静态库,

比较诧异,经过反复试验,发现如果没有libevent动态库,就不会生成thfirtnb静态库

由于编译安装第三方库时,习惯使用--disable-shared仅生成静态库,导致了问题的出现

另外,在编译安装libevent时,configure默认同时生成静态库和动态库

configure -h可以发现默认使用参数--enable-static --enable-shared

以上是以Apache Thrift v0.8.0和libevent-2.0.20-stable进行测试得出的结论

vieyahn2017 commented 5 years ago

/usr/bin/ld: cannot find -l**** 问题的解决办法

https://blog.csdn.net/qq_39436605/article/details/80893885 2018年07月03日 09:46:55 我是小超斌 阅读数:5369更多 个人分类: LINUX 在ubuntu上安装软件时,经常出现这样的问题:

/usr/bin/ld: cannot find -l****

例如:

/usr/bin/ld: cannot find -lgfortran 安装torch时出现 
/usr/bin/ld: cannot find -lstdc++ 安装cuda时出现 

这些问题都是因为找不到相应的lib文件,以上面的例子来说就是在系统中找不到libgfortran.so、libstdc++.so文件。

以libgfortran.so为例,我们先在系统中查找下该文件。命令为:

locate libgfortran 

结果显示如下: 这里写图片描述

可以看到,有libgfortran.so.文件存在,但是没有libgfortran.so文件,因此我们进入/usr/lib/x86_64-linux-gnu/目录中,新建一个libgfortran.so的软连接,使其链接到已有的libgfortran.so文件(如libgfortran.so.3)。命令为:

sudo ln -s libgfortran.so.3 libgfortran.so

完成后查看下所有libgfortran.so文件ll libgfortran.so*

到此,该错误已经解决。

类似的/usr/bin/ld: cannot find -l****问题都可以通过这种方法解决。

vieyahn2017 commented 5 years ago

缺少动态链接库: libthrift-0.9.3.so: cannot open shared object file: No such file or directory

2016年04月25日 11:10:41 runnerchen1 阅读数:4094 [root@localhost gen-cpp]# ./CppServer ./CppServer: error while loading shared libraries: libthrift-0.9.3.so: cannot open shared object file: No such file or directory [root@localhost gen-cpp]# ldd CppServer linux-vdso.so.1 => (0x00007ffcd4181000) libthrift-0.9.3.so => not found libstdc++.so.6 => /lib64/libstdc++.so.6 (0x00007f7a547ef000) libm.so.6 => /lib64/libm.so.6 (0x00007f7a544ed000) libgcc_s.so.1 => /lib64/libgcc_s.so.1 (0x00007f7a542d7000) libc.so.6 => /lib64/libc.so.6 (0x00007f7a53f15000) libpthread.so.0 => /lib64/libpthread.so.0 (0x00007f7a53cf9000) /lib64/ld-linux-x86-64.so.2 (0x00007f7a54b21000)

临时解决方法:

 export LD_LIBRARY_PATH=/usr/local/lib

不行

这样找文件也没有

find / -iname lthriftnb.so

不知道

上面说的libevent之前安装没弄好,

是不是这样。

不测这个了。。。。。

vieyahn2017 commented 5 years ago

用g++编译ok

后面用g++编译ok

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 Serv_server.skeleton.cpp -L/usr/local/lib/*.so -lthrift -o server

不过也要导入环境变量,再运行

 export LD_LIBRARY_PATH=/usr/local/lib
./server
vieyahn2017 commented 5 years ago

现在的例子, server采用cmake编译不成功,client也不靠谱

因此,写了

python客户端


import sys
import glob
sys.path.append('gen-py')

from thrift import Thrift
from thrift.transport import TSocket
from thrift.transport import TTransport
from thrift.protocol import TBinaryProtocol

from student.Serv import Client
from student.ttypes import Student

def print_st(stu):
    print("num is: %s \n" % stu.sno)
    print("name is: %s \n" % stu.sname)
    if stu.ssex:
        print("sex is: man! \n")
    else:
        print("sex is: woman! \n")
    if stu.sage is None:
        age = 18
    print("age is: %s \n" % stu.sage)

def main():
    transport=TSocket.TSocket('localhost', 9090)
    transport=TTransport.TBufferedTransport(transport)
    protocol=TBinaryProtocol.TBinaryProtocol(transport)
    client=Client(protocol)
    transport.open()
    st = Student(222, "shuishuijiang", False, 16)
    print_st(st)

    st_b = client.put(st)
    print_st(st_b)

    send = "hello server!"
    rec = client.hello_word(send)
    print("Server say: %s\n", rec)

    transport.close()

if __name__ == '__main__':
    main()

启动服务端,执行本客户端,响应如下

num is: 222

name is: shuishuijiang

sex is: woman!

age is: 16

num is: 0

name is: shuishuihaoren

sex is: man!

age is: 0

('Server say: %s\n', u'Hi, client!')

表明是ok的

vieyahn2017 commented 5 years ago

g++ 编译成功,是来自下面这个帖子的例子

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

2017年04月13日 18:39:33 Hao973 阅读数:9755 版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/feng973/article/details/70160571

vieyahn2017 commented 5 years ago

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

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 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

//服务器 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