01-Thrift初探

来源:互联网 发布:图书管理数据库系统 编辑:程序博客网 时间:2024/06/07 03:04

  • Thrift初探
  • 接口文件
  • 编写服务器
  • 编写客户端
  • Go语言版本
    • 1 服务器端
    • 2 客户端版
    • 3 自带Remote客户端
  • 简单总结

Thrift初探

目标是编写一个最简单的服务器+客户端

1 接口文件

我们先实现一个最简单的加法服务器:

// MathService.thriftservice MathService {    i32 Add(1:i32 A, 2:i32 B)}

使用下载(或编译)的Thrift工具,生成调用代码:

mkdir mysrc // 必须先创建输出目录thrift -o . -out mysrc --gen cpp MathService.thrift  //c++源代码thrift -o . -out mysrc --gen go MathService.thrift  //golang源代码

目录结构:

C:\xxx\MYSRC│  MathService.cpp│  MathService.h│  MathService_constants.cpp│  MathService_constants.h│  MathService_server.skeleton.cpp│  MathService_types.cpp│  MathService_types.h│└─mathservice    │  GoUnusedProtection__.go    │  MathService-consts.go    │  MathService.go    │    └─math_service-remote            math_service-remote.go

其中,mathservice目录下是go的代码。根目录下的h和cpp文件是c++代码。

2 编写服务器

其实生成的代码中已经将服务器写好了,MathService_server.skeleton.cpp如果需要其他特殊需求,可参考这个Demo进行修改。
我们创建一个项目,然后将它们都加入进入进去。
通过Nuget安装Boost-vc140,libevent-vc120, openssl。(后续编译过程很多坑,反而不建议了)

#include "MathService.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 MathServiceHandler : virtual public MathServiceIf { public:  MathServiceHandler() {    // Your initialization goes here  }  // Add 函数的服务器实现  int32_t Add(const int32_t A, const int32_t B) {    printf("Add %d + %d\n", A, B);    return A+B;  }};int main(int argc, char **argv) {  int port = 9090;  shared_ptr<MathServiceHandler> handler(new MathServiceHandler());  shared_ptr<TProcessor> processor(new MathServiceProcessor(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;}

Thrift代码的大坑
在编译libthrift时各种通不过,主要有如下问题:

  1. boost开头的文件找不到
    解决办法:直接手动指定boost库的头文件所在。

  2. 一大堆的libThrift函数找不到(这个问题太坑,网上搜不到比较准确的答案)
    unresolved external symbol "public: virtual void __cdecl apache::thrift::server::TServerFramework::serve(void)" (?serve@TServerFramework@server@thrift@apache@@UEAAXXZ)
    解决办法:将server文件夹中的,TConnectedClient 和 TServerFramework 头文件和cpp都手工添加到libthrift项目中。

  3. MathService函数错误
    解决办法:在 MathService_server.skeleton.cpp 中,对Add函数进行了实现,但是没有返回值,只需要在Add中增加一个return 返回就行了。

3 编写客户端

#include "MathService.h"#include <thrift/protocol/TBinaryProtocol.h>#include <thrift/transport/TSocket.h>#include <thrift/transport/TBufferTransports.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) {  int port = 9090;  shared_ptr<TTransport> clientSocket(new TSocket("127.0.0.1", port));  shared_ptr<TTransport> clientTransport(new TBufferedTransport(clientSocket));  shared_ptr<TProtocol> clientProtocol(new TBinaryProtocol(clientTransport));  MathServiceClient client(clientProtocol);  try  {      clientTransport->open();      printf("Open Remote Transport, wait call it!\n");      getchar();      for ( int i=0;i<100;i++ )      {          int nRet = client.Add(i, i);          printf("[%03d] %d + %d = %d\n", i, i, i, nRet);      }  }  catch (TException& e)  {      printf("ERROR:%s\n", e.what());  }  system("pause");  return 0;}

4 Go语言版本

前提:安装配置好Go环境。本人使用go1.8.3版本测试通过。

需要将mathservice文件夹放到$GOPATH/src文件夹下,然后在math_service-remote文件夹下编写client.go和server.go文件。

4.1 服务器端

// server.gopackage mainimport (    "fmt"    "mathservice"    "os"    "git.apache.org/thrift.git/lib/go/thrift")const (    NetWorkAddr = "127.0.0.1:9090")type MyMathService struct {}func (this *MyMathService) Add(A int32, B int32) (r int32, err error) {    r = A + B    err = nil    fmt.Println("Add", A, B)    return}func main() {    handler := &MyMathService{}    processor := mathservice.NewMathServiceProcessor(handler)    serverTransport, err := thrift.NewTServerSocket(NetWorkAddr)    if err != nil {        fmt.Println("Error!", err)        os.Exit(1)    }    transportFactory := thrift.NewTBufferedTransportFactory(512) // c++版本默认大小是512    //protocolFactory := thrift.NewTCompactProtocolFactory()    protocolFactory := thrift.NewTBinaryProtocolFactoryDefault()    server := thrift.NewTSimpleServer4(processor, serverTransport, transportFactory, protocolFactory)    fmt.Println("thrift server in", NetWorkAddr)    server.Serve()}

4.2 客户端版

// client.gopackage mainimport (    "mathservice"    "fmt"    "os"    "git.apache.org/thrift.git/lib/go/thrift")func main() {    client_socket, _ := thrift.NewTSocket("127.0.0.1:9090")    client_transport := thrift.NewTBufferedTransport(client_socket, 512)    protocolFactory := thrift.NewTBinaryProtocolFactoryDefault()    client := mathservice.NewMathServiceClientFactory(client_transport, protocolFactory)    if err := client_transport.Open(); err != nil {        fmt.Fprintln(os.Stderr, "Error opening socket", err)        os.Exit(1)    }    defer client_transport.Close()    for i := int32(0); i < 100; i++ {        nRet, _ := client.Add(i, i)        fmt.Println(i, "Add", nRet)    }    fmt.Println("Over!")}

4.3 自带Remote客户端

自带的math_service-remote.go是一个很不错的Client学习对象,-P可指定编码方式,-frame可指定帧传输模式,还可以随意指定函数和参数,真的是做的很全面啦!

测试指令go run math_service-remote.go -P binary -h 127.0.0.1 -p 9090 Add 123 888

5 简单总结

使用C++编译使用时,有很多坑存在,作为一个大名鼎鼎的开源项目,文档很少,学习体验很差,真的是让人心烦!相对而言,使用Go编写使用时,体验很不错,唯一的问题就是,文档太少!!!!!!!!