golang thrift 总结一下网络上的一些坑

我们以hello world来大概分析一下golang中的thrift包,并且扒一扒网络上有关thrift的一些坑

查看源码,服务器定义如下:(详见simple_server.go文件)

type TSimpleServer struct { quit chan struct{} stopped int64 processorFactory TProcessorFactory //实质是一个handler,用来相应客户端的请求 serverTransport TServerTransport //实质是一个socket inputTransportFactory TTransportFactory //实质是传输协议的具体操作类(详细可见transport.go文件中TTransport结构体) outputTransportFactory TTransportFactory // inputProtocolFactory TProtocolFactory //实质是传输协议(有compact、simplejson、json、binary四种协议,默认是binary)
tputProtocolFactory TProtocolFactory // }
@L_404_1@

在go语言中,创建一个thrift服务器有三种方法:(详见simple_server.go文件)

func NewTSimpleServer2(processor TProcessor,serverTransport TServerTransport) *TSimpleServer { return NewTSimpleServerFactory2(NewTProcessorFactory(processor),serverTransport) } func NewTSimpleServer4(processor TProcessor,serverTransport TServerTransport,transportFactory TTransportFactory,protocolFactory TProtocolFactory) *TSimpleServer {  NewTSimpleServerFactory4(NewTProcessorFactory(processor),serverTransport,transportFactory,protocolFactory,) } func NewTSimpleServer6(processor TProcessor,inputTransportFactory TTransportFactory,outputTransportFactory TTransportFactory,inputProtocolFactory TProtocolFactory,outputProtocolFactory TProtocolFactory) *TSimpleServer {  NewTSimpleServerFactory6(NewTProcessorFactory(processor),inputTransportFactory,outputTransportFactory,inputProtocolFactory,outputProtocolFactory,) }
@L_404_1@

这三个函数分别调用了工厂函数

NewTSimpleServerFactory2;
NewTSimpleServerFactory4;
NewTSimpleServerFactory6;
func NewTSimpleServerFactory2(processorFactory TProcessorFactory,255); line-height:1.5!important">return NewTSimpleServerFactory6(processorFactory,NewTTransportFactory(),NewTBinaryProtocolFactoryDefault(),) } func NewTSimpleServerFactory4(processorFactory TProcessorFactory,) } func NewTSimpleServerFactory6(processorFactory TProcessorFactory,255); line-height:1.5!important">return &TSimpleServer{ processorFactory: processorFactory,serverTransport: serverTransport,inputTransportFactory: inputTransportFactory,outputTransportFactory: outputTransportFactory,inputProtocolFactory: inputProtocolFactory,outputProtocolFactory: outputProtocolFactory,quit: make(chan struct{},1),} }
@L_404_1@

好啦!现在假如我们需要创建一个以二进制协议传输的thrift服务器,那么可以用如下代码简单实现:

    serverTransport,err := thrift.NewTServerSocket("127.0.0.1:8808") if err != nil { fmt.Println(Error!",err) return } handler := &rpcService{} processor := rpc.NewRpcServiceProcessor(handler) server := thrift.NewTSimpleServer2(processor,serverTransport) fmt.Println(thrift server in localhost") server.Serve()
@L_404_1@

另外我在网上查看这方面资料的时候,发现大家都用的NewTSimpleServer4这个函数,然后自己又创建一遍NewTTransportFactory以及NewTBinaryProtocolFactoryDefault。

现在我们分析一下源码,发现此举实乃多此一举。这是第一坑。

接下来说说如何用golang thrift编写客户端,查看网络上的一些写法,发现根本用不了,服务器会阻塞住!还是从源码来分析:

在thrift自动生成代码中,会生成一个关于客户端的示例。

@L_404_1@
// Autogenerated by Thrift Compiler (0.9.3)  DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING
 package main import ( flag"
    fmtgit.apache.org/thrift.git/lib/go/thriftmathnetnet/urlosstrconvstringsvic/rpc" ) func Usage() { fmt.Fprintln(os.Stderr,Usage of ",os.Args[0],0); line-height:1.5!important"> [-h host:port] [-u url] [-f[ramed]] function [arg1 [arg2...]]:") flag.PrintDefaults() fmt.Fprintln(os.Stderr,0); line-height:1.5!important">\nFunctions:") fmt.Fprintln(os.Stderr,0); line-height:1.5!important"> Video request(string vid,string cid,string platform,string url,string clientVersion)") fmt.Fprintln(os.Stderr) os.Exit(0) } func main() { flag.Usage = Usage var host string
    var port int
    var protocol var urlString var framed bool
    var useHttp var parsedUrl url.URL var trans thrift.TTransport _ = strconv.Atoi _ = math.Abs flag.Usage = Usage flag.StringVar(&host,0); line-height:1.5!important">hlocalhostSpecify host and port") flag.IntVar(&port,0); line-height:1.5!important">p9090,0); line-height:1.5!important">Specify port") flag.StringVar(&protocol,0); line-height:1.5!important">PbinarySpecify the protocol (binary,compact,simplejson,json)") flag.StringVar(&urlString,0); line-height:1.5!important">u"",0); line-height:1.5!important">Specify the url") flag.BoolVar(&framed,0); line-height:1.5!important">framedfalse,0); line-height:1.5!important">Use framed transport") flag.BoolVar(&useHttp,0); line-height:1.5!important">httpUse http") flag.Parse() if len(urlString) > 0 { parsedUrl,err := url.Parse(urlString) if err != nil { fmt.Fprintln(os.Stderr,0); line-height:1.5!important">Error parsing URL:  parsedUrl.Host useHttp = len(parsedUrl.Scheme) <= 0 || parsedUrl.Scheme == " } else if useHttp { _,err := url.Parse(fmt.Sprint(http://:= flag.Arg(0) var err error if useHttp { trans,err = thrift.NewTHttpClient(parsedUrl.String()) } else { portStr := fmt.Sprint(port) if strings.Contains(host,0); line-height:1.5!important">") { host,portStr,err = net.SplitHostPort(host) error with host:1) } } trans,err = thrift.NewTSocket(net.JoinHostPort(host,portStr)) error resolving address:1) } if framed { trans = thrift.NewTFramedTransport(trans) } } Error creating transport1) } defer trans.Close() var protocolFactory thrift.TProtocolFactory switch protocol { case compact": protocolFactory = thrift.NewTCompactProtocolFactory() break
    simplejson": protocolFactory = thrift.NewTSimpleJSONProtocolFactory() json": protocolFactory = thrift.NewTJSONProtocolFactory() "": protocolFactory = thrift.NewTBinaryProtocolFactoryDefault() default: fmt.Fprintln(os.Stderr,0); line-height:1.5!important">Invalid protocol specified: 1) } client := rpc.NewVideoServiceClientFactory(trans,protocolFactory) if err := trans.Open(); err != nil { fmt.Fprintln(os.Stderr,0); line-height:1.5!important">Error opening socket to " switch cmd { request": if flag.NArg()-1 != 5 { fmt.Fprintln(os.Stderr,0); line-height:1.5!important">Request requires 5 args") flag.Usage() } argvalue0 := flag.Arg(1) value0 := argvalue0 argvalue1 := flag.Arg(2) value1 := argvalue1 argvalue2 := flag.Arg(3) value2 := argvalue2 argvalue3 := flag.Arg(4) value3 := argvalue3 argvalue4 := flag.Arg(5) value4 := argvalue4 fmt.Print(client.Request(value0,value1,value2,value3,value4)) fmt.Print(\n"": Usage() Invalid function  
   @L_404_1@ 
  

我们一部分一部分来分析分析:

flag.Usage = Usage ") flag.Parse()
@L_404_1@

这些代码是设置了一些程序的启动命令,例如默认地址是loacalhost,我们可以根据client.exe -h xxx.xxx.xxx.xxx之类的命令来修改

我们发现这些代码都不是我们需要的,pass,继续看

if useHttp { trans,err = thrift.NewTHttpClient(parsedUrl.String()) } 1) } } = thrift.NewTSocket(net.JoinHostPort(host,portStr)) if framed { trans = thrift.NewTFramedTransport(trans) } }

@L_404_1@

这部分主要作用是解析url参数,从中取得host以及port。并且用于生成一个TTransport,上面红线加粗的函数定义在源码中如下:

func NewTHttpClient(urlstr string) (TTransport,error) { return NewTHttpClientWithOptions(urlstr,THttpClientOptions{}) } func NewTSocket(hostPort string) (*TSocket,255); line-height:1.5!important">return NewTSocketTimeout(hostPort,128); line-height:1.5!important">0) }
@L_404_1@

细心的朋友们可能发现了端倪,第二个函数的返回值是一个TSocket指针,并不是TTransport,是不是有啥问题?不急,我们看看这两个结构体的定义就知道了:

    type TTransport interface { io.ReadWriteCloser Flusher ReadSizeProvider  Opens the transport for communication
 Open() error  Returns true if the transport is open
    IsOpen() bool }
@L_404_1@

原来TTransport是一个接口类型,而TSocket则实现了该接口!

目前为止,我们获得了创建客户端所需要的关键代码

trans,err = thrift.NewTHttpClient(parsedUrl.String()) trans,err = thrift.NewTSocket(net.JoinHostPort(host,portStr))

OK,继续分析示例!

 var protocolFactory thrift.TProtocolFactory 1) } client := rpc.NewVideoServiceClientFactory(trans,protocolFactory) 1) }
@L_404_1@

switch语句是根据我们所输入的参数,选择传输协议。最后通过NewVideoServiceClientFactory函数 完成客户端的创建

最后,总结一下,假如我们要创建一个以二进制为传输协议,那么我们可以编写如下代码来完成:

    transport,err := thrift.NewTSocket(net.JoinHostPort(127.0.0.18808")) 1) } protocolFactory := thrift.NewTBinaryProtocolFactoryDefault() client := NewRpcServiceClientFactory(transport,255); line-height:1.5!important">if err := transport.Open(); err != nil { fmt.Fprintln(os.Stderr,0); line-height:1.5!important">Error opening socket to 127.0.0.1:88081) } defer transport.Close() res,_ := client.SayHi(“World”)

相关文章

程序目录结构 简单实现,用户登录后返回一个jwt的token,下次请求带上token请求用户信息接口并返回信息...
本篇博客的主要内容是用go写一个简单的Proof-of-Work共识机制,不涉及到网络通信环节,只是一个本地的简...
简介 默克尔树(MerkleTree)是一种典型的二叉树结构,其主要特点为: 最下面的叶节点包含存储数据或其...
接下来学习并发编程, 并发编程是go语言最有特色的地方, go对并发编程是原生支持. goroutine是go中最近本...
先普及一下, 什么是广度优先搜索 广度优先搜索类似于树的层次遍历。从图中的某一顶点出发,遍历每一个顶...
第一天: 接口的定义和实现 第二天: 一. go语言是面向接口编程. 在学习继承的时候说过, go语言只有封装,...