thrift学习

88 篇文章 0 订阅
2 篇文章 0 订阅

目录

安装

编写.thrift文件

注释

变量类型

结构体 struct

自定义类型

常量 const

枚举 enum

异常 exception

service

method

 完整的service定义

查看安装的thrift版本

切换thrift版本

编译.thrift文件

tutorial.thrift

tutorual.go里面的内容

interface

HelloClient

HelloPingArgs

HelloPingResult

HelloMethodNameResult_Success_DEFAULT

HelloProcessor

helloProcessorPing


参考教程:http://thrift.apache.org/tutorial/go

安装

git clone https://github.com/apache/thrift.git

编写.thrift文件

tutorial.thrift: https://github.com/apache/thrift/blob/master/tutorial/tutorial.thrift

在这个文件里面其实已经写明了thrift文件的数据类型,格式等信息。

.thrift文件支持标准的shell注释

在运行.thrift文件之前需要安装thrift编译器在/usr/local/bin下

注释

单行注释: //

多行注释: /**  */

变量类型

 *  bool        Boolean, one byte
 *  i8 (byte)   Signed 8-bit integer
 *  i16         Signed 16-bit integer
 *  i32         Signed 32-bit integer
 *  i64         Signed 64-bit integer
 *  double      64-bit floating point value
 *  string      String
 *  binary      Blob (byte array)
 *  map<t1,t2>  Map from one type to another
 *  list<t1>    Ordered list of one type
 *  set<t1>     Set of unique elements of one type

结构体 struct

struct是基本的复杂的数据结构,由字段组成,每个字段都有一个整数标识符,类型,变量名,以及一个可选的默认值。

Structs are the basic complex data structures. They are comprised of fields
which each have an integer identifier, a type, a symbolic name, and an
optional default value.

 字段可以被声明为“optional”的,如果没有设置值,能确保不会包含在序列化输出结果中。

Fields can be declared "optional", which ensures they will not be included
 in the serialized output if they aren't set.  Note that this requires some
 manual management in some languages.

自定义类型

// typedef 变量类型 变量名 
typedef i32 MyInteger

常量 const

复杂的类型和结构体通常以json格式展示

const i32 INT32CONSTANT = 9853
const map<string,string> MAPCONSTANT = {'hello':'world', 'goodnight':'moon'}

枚举 enum

是32位整数,值是可选的,如果没有提供,则从1开始。

 You can define enums, which are just 32 bit integers. Values are optional
and start at 1 if not supplied, C style again.

异常 exception

exception InvalidOperation {
  1: i32 whatOp,
  2: string why
}

service

service定义仅仅需要一个service name,如果需要继承其他service的,使用extends关键字

service FirstService {
    
}

// 继承其他service
service SecondService extends FirstService {
    
}

method

method的定义类似C。有一个返回类型,参数以及可选的可能会抛出的异常。

 void ping(),

   i32 add(1:i32 num1, 2:i32 num2),

   i32 calculate(1:i32 logid, 2:Work w) throws (1:InvalidOperation ouch),

 oneway 修饰的method

This method has a oneway modifier. That means the client only makes
a request and does not listen for any response at all. Oneway methods
must be void.
// 当方法使用oneway修饰的时候,返回类型必须是void,意味着客户端发送请求后并不需要监听任何的返回结果
oneway void zip() 

 完整的service定义

service MyService {
    void ping(),
    string PING(1:string msg),
}

查看安装的thrift版本

thrift -version

切换thrift版本

cd 到thrift目录,执行

git checkout 0.10.0 // 指定的版本号

编译.thrift文件

thrift -r --gen go tutorial.thrift

tutorial.thrift

namespace go demo

service Hello {
    string ping(1:string msg)
    i32 sum(1:i32 num1, 2:i32 num2)
}

当执行thrift -r --gen go tutorial.thrift编译以后会在与tutoraul.thrift同级的目录生成gen-go目录,下一层目录是.thrift里面的namespace。

由于我的service名称为hello,所以生成了hello-remote,代表远程的。

tutorual.go里面的内容(thrift版本不一样,内容也会不一样,我这里的版本0.12.0)

tutorial.go的package为.thrift里面的namespace。

interface

type Hello interface {
  // Parameters:
  //  - Msg
  Ping(ctx context.Context, msg string) (r string, err error)
  // Parameters:
  //  - Num1
  //  - Num2
  Sum(ctx context.Context, num1 int32, num2 int32) (r int32, err error)
}

client相关

HelloClient

type HelloClient struct {
  c thrift.TClient
}

func NewHelloClientFactory(t thrift.TTransport, f thrift.TProtocolFactory) *HelloClient {
  return &HelloClient{
    c: thrift.NewTStandardClient(f.GetProtocol(t), f.GetProtocol(t)),
  }
}

func NewHelloClientProtocol(t thrift.TTransport, iprot thrift.TProtocol, oprot thrift.TProtocol) *HelloClient {
  return &HelloClient{
    c: thrift.NewTStandardClient(iprot, oprot),
  }
}

func NewHelloClient(c thrift.TClient) *HelloClient {
  return &HelloClient{
    c: c,
  }
}

func (p *HelloClient) Client_() thrift.TClient {
  return p.c
}
// Parameters:
//  - Msg
func (p *HelloClient) Ping(ctx context.Context, msg string) (r string, err error) {
  var _args0 HelloPingArgs
  _args0.Msg = msg
  var _result1 HelloPingResult
   // 客户端调用ping方法并指定参数,如果出错直接返回,如果成功会调用GetSuccess()获取结果
  if err = p.Client_().Call(ctx, "ping", &_args0, &_result1); err != nil {
    return
  }
  return _result1.GetSuccess(), nil
}

HelloPingArgs

// HELPER FUNCTIONS AND STRUCTURES

// Attributes:
//  - Msg
type HelloPingArgs struct {
  Msg string `thrift:"msg,1" db:"msg" json:"msg"`
}

func NewHelloPingArgs() *HelloPingArgs {
  return &HelloPingArgs{}
}


func (p *HelloPingArgs) GetMsg() string {
  return p.Msg
}
func (p *HelloPingArgs) Read(iprot thrift.TProtocol) error {
  if _, err := iprot.ReadStructBegin(); err != nil {
    return thrift.PrependError(fmt.Sprintf("%T read error: ", p), err)
  }


  for {
    _, fieldTypeId, fieldId, err := iprot.ReadFieldBegin()
    if err != nil {
      return thrift.PrependError(fmt.Sprintf("%T field %d read error: ", p, fieldId), err)
    }
    if fieldTypeId == thrift.STOP { break; }
    switch fieldId {
    case 1:
      if fieldTypeId == thrift.STRING {
        if err := p.ReadField1(iprot); err != nil {
          return err
        }
      } else {
        if err := iprot.Skip(fieldTypeId); err != nil {
          return err
        }
      }
    default:
      if err := iprot.Skip(fieldTypeId); err != nil {
        return err
      }
    }
    if err := iprot.ReadFieldEnd(); err != nil {
      return err
    }
  }
  if err := iprot.ReadStructEnd(); err != nil {
    return thrift.PrependError(fmt.Sprintf("%T read struct end error: ", p), err)
  }
  return nil
}

func (p *HelloPingArgs)  ReadField1(iprot thrift.TProtocol) error {
  if v, err := iprot.ReadString(); err != nil {
  return thrift.PrependError("error reading field 1: ", err)
} else {
  p.Msg = v
}
  return nil
}

func (p *HelloPingArgs) Write(oprot thrift.TProtocol) error {
  if err := oprot.WriteStructBegin("ping_args"); err != nil {
    return thrift.PrependError(fmt.Sprintf("%T write struct begin error: ", p), err) }
  if p != nil {
    if err := p.writeField1(oprot); err != nil { return err }
  }
  if err := oprot.WriteFieldStop(); err != nil {
    return thrift.PrependError("write field stop error: ", err) }
  if err := oprot.WriteStructEnd(); err != nil {
    return thrift.PrependError("write struct stop error: ", err) }
  return nil
}

func (p *HelloPingArgs) writeField1(oprot thrift.TProtocol) (err error) {
  if err := oprot.WriteFieldBegin("msg", thrift.STRING, 1); err != nil {
    return thrift.PrependError(fmt.Sprintf("%T write field begin error 1:msg: ", p), err) }
  if err := oprot.WriteString(string(p.Msg)); err != nil {
  return thrift.PrependError(fmt.Sprintf("%T.msg (1) field write error: ", p), err) }
  if err := oprot.WriteFieldEnd(); err != nil {
    return thrift.PrependError(fmt.Sprintf("%T write field end error 1:msg: ", p), err) }
  return err
}

func (p *HelloPingArgs) String() string {
  if p == nil {
    return "<nil>"
  }
  return fmt.Sprintf("HelloPingArgs(%+v)", *p)
}

HelloPingResult

// Attributes:
//  - Success
type HelloPingResult struct {
  Success *string `thrift:"success,0" db:"success" json:"success,omitempty"`
}

func NewHelloPingResult() *HelloPingResult {
  return &HelloPingResult{}
}

var HelloPingResult_Success_DEFAULT string
func (p *HelloPingResult) GetSuccess() string {
  if !p.IsSetSuccess() {
    return HelloPingResult_Success_DEFAULT
  }
return *p.Success
}
func (p *HelloPingResult) IsSetSuccess() bool {
  return p.Success != nil
}

func (p *HelloPingResult) Read(iprot thrift.TProtocol) error {
  if _, err := iprot.ReadStructBegin(); err != nil {
    return thrift.PrependError(fmt.Sprintf("%T read error: ", p), err)
  }


  for {
    _, fieldTypeId, fieldId, err := iprot.ReadFieldBegin()
    if err != nil {
      return thrift.PrependError(fmt.Sprintf("%T field %d read error: ", p, fieldId), err)
    }
    if fieldTypeId == thrift.STOP { break; }
    switch fieldId {
    case 0:
      if fieldTypeId == thrift.STRING {
        if err := p.ReadField0(iprot); err != nil {
          return err
        }
      } else {
        if err := iprot.Skip(fieldTypeId); err != nil {
          return err
        }
      }
    default:
      if err := iprot.Skip(fieldTypeId); err != nil {
        return err
      }
    }
    if err := iprot.ReadFieldEnd(); err != nil {
      return err
    }
  }
  if err := iprot.ReadStructEnd(); err != nil {
    return thrift.PrependError(fmt.Sprintf("%T read struct end error: ", p), err)
  }
  return nil
}

func (p *HelloPingResult)  ReadField0(iprot thrift.TProtocol) error {
  if v, err := iprot.ReadString(); err != nil {
  return thrift.PrependError("error reading field 0: ", err)
} else {
  p.Success = &v
}
  return nil
}

func (p *HelloPingResult) Write(oprot thrift.TProtocol) error {
  if err := oprot.WriteStructBegin("ping_result"); err != nil {
    return thrift.PrependError(fmt.Sprintf("%T write struct begin error: ", p), err) }
  if p != nil {
    if err := p.writeField0(oprot); err != nil { return err }
  }
  if err := oprot.WriteFieldStop(); err != nil {
    return thrift.PrependError("write field stop error: ", err) }
  if err := oprot.WriteStructEnd(); err != nil {
    return thrift.PrependError("write struct stop error: ", err) }
  return nil
}

func (p *HelloPingResult) writeField0(oprot thrift.TProtocol) (err error) {
  if p.IsSetSuccess() {
    if err := oprot.WriteFieldBegin("success", thrift.STRING, 0); err != nil {
      return thrift.PrependError(fmt.Sprintf("%T write field begin error 0:success: ", p), err) }
    if err := oprot.WriteString(string(*p.Success)); err != nil {
    return thrift.PrependError(fmt.Sprintf("%T.success (0) field write error: ", p), err) }
    if err := oprot.WriteFieldEnd(); err != nil {
      return thrift.PrependError(fmt.Sprintf("%T write field end error 0:success: ", p), err) }
  }
  return err
}

func (p *HelloPingResult) String() string {
  if p == nil {
    return "<nil>"
  }
  return fmt.Sprintf("HelloPingResult(%+v)", *p)
}

HelloMethodNameResult这个结构体里面都只会包含一个字段:Success:(methodName是你定义的方法的名称)

Success *int32 `thrift:"success,0" db:"success" json:"success,omitempty"`

HelloMethodNameResult_Success_DEFAULT

与HelloMethodName相关的还有一个变量:HelloMethodNameResult_Success_DEFAULT,变量类型是跟你接口方法返回的类型一致的。比如我这里的Sum()方法返回类型为int32,那么我的这个HelloSumResult_Success_DEFAULT类型即为int32

var HelloSumResult_Success_DEFAULT int32
func (p *HelloSumResult) GetSuccess() int32 {
  if !p.IsSetSuccess() {
    return HelloSumResult_Success_DEFAULT
  }
    return *p.Success
}

func (p *HelloSumResult) IsSetSuccess() bool {
   return p.Success != nil
}

HelloProcessor

type HelloProcessor struct {
  processorMap map[string]thrift.TProcessorFunction
  handler Hello
}

func (p *HelloProcessor) AddToProcessorMap(key string, processor thrift.TProcessorFunction) {
  p.processorMap[key] = processor
}

func (p *HelloProcessor) GetProcessorFunction(key string) (processor thrift.TProcessorFunction, ok bool) {
  processor, ok = p.processorMap[key]
  return processor, ok
}

func (p *HelloProcessor) ProcessorMap() map[string]thrift.TProcessorFunction {
  return p.processorMap
}

func NewHelloProcessor(handler Hello) *HelloProcessor {

  self4 := &HelloProcessor{handler:handler, processorMap:make(map[string]thrift.TProcessorFunction)}
  self4.processorMap["ping"] = &helloProcessorPing{handler:handler}
  self4.processorMap["sum"] = &helloProcessorSum{handler:handler}
return self4
}

func (p *HelloProcessor) Process(ctx context.Context, iprot, oprot thrift.TProtocol) (success bool, err thrift.TException) {
  // 这里ReadMessageBegin其实是读取的是helloProcessorPing的Process方法里面的WriteMessageBegin写入的内容,即method name,序列号
  name, _, seqId, err := iprot.ReadMessageBegin()
  if err != nil { return false, err }
  if processor, ok := p.GetProcessorFunction(name); ok {
    return processor.Process(ctx, seqId, iprot, oprot)
  }
  iprot.Skip(thrift.STRUCT)
  iprot.ReadMessageEnd()
  x5 := thrift.NewTApplicationException(thrift.UNKNOWN_METHOD, "Unknown function " + name)
  oprot.WriteMessageBegin(name, thrift.EXCEPTION, seqId)
  x5.Write(oprot)
  oprot.WriteMessageEnd()
  oprot.Flush(ctx)
  return false, x5

}

helloProcessorPing

type helloProcessorPing struct {
  handler Hello
}

func (p *helloProcessorPing) Process(ctx context.Context, seqId int32, iprot, oprot thrift.TProtocol) (success bool, err thrift.TException) {
  args := HelloPingArgs{}
   // 这里读取请求参数结构体里面的内容,即调用iprot.ReadStructBegin(),成功以后再调用for循环一直调用:iprot.ReadFieldBegin(),读取每个字段。如果有err,那么调用iprot.ReadMessageEnd(),再抛出异常,并将err write出去
  if err = args.Read(iprot); err != nil {
    iprot.ReadMessageEnd()
    x := thrift.NewTApplicationException(thrift.PROTOCOL_ERROR, err.Error())
    oprot.WriteMessageBegin("ping", thrift.EXCEPTION, seqId)
    x.Write(oprot)
    oprot.WriteMessageEnd()
    oprot.Flush(ctx)
    return false, err
  }
  // 请求参数正常读取结束
  iprot.ReadMessageEnd()
  result := HelloPingResult{}
  var retval string
  var err2 error
  // 调用ping(),如果出错,write err msg  
  if retval, err2 = p.handler.Ping(ctx, args.Msg); err2 != nil {
    x := thrift.NewTApplicationException(thrift.INTERNAL_ERROR, "Internal error processing ping: " + err2.Error())
    oprot.WriteMessageBegin("ping", thrift.EXCEPTION, seqId)
    x.Write(oprot)
    oprot.WriteMessageEnd()
    oprot.Flush(ctx)
    return true, err2
  } else {
    result.Success = &retval
}
  // 调用成功,将成功消息write出去,在HelloProcessor的Process里面调用readMessage方法
  if err2 = oprot.WriteMessageBegin("ping", thrift.REPLY, seqId); err2 != nil {
    err = err2
  }
  if err2 = result.Write(oprot); err == nil && err2 != nil {
    err = err2
  }
  if err2 = oprot.WriteMessageEnd(); err == nil && err2 != nil {
    err = err2
  }
  if err2 = oprot.Flush(ctx); err == nil && err2 != nil {
    err = err2
  }
  if err != nil {
    return
  }
  return true, err
}

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值