01-Thrift初探

Thrift初探

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

1 接口文件

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

// MathService.thrift
service 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.go
package main

import (
    "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.go
package main

import (
    "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编写使用时,体验很不错,唯一的问题就是,文档太少!!!!!!!!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值