自从gRPC出来,Thrift与gPRC竞争日益激烈,他们都有不同的适合的应用场景,就目前来看,我个人更喜欢Thrift一点,最近使用了新版0.11.0以及未正式发布的0.12.0,发现了很大的问题:
下面来解决这些问题:
首先,需要注意的是,package版本和thrift版本并不是严格的一一对应,除了C++版本,其他版本多多少少都会有与golang版本类似问题。这些问题产生的核心原因是后期版本对于Context的支持,导致接口和调用都产生了变化。
参考之前的博客点这里,我以类似项目为例,一步步解释:
新建golang项目thrifttest
thrift文件,内容不变:
// mydef.thrift
service MathService {
i32 Add(1:i32 A, 2:i32 B)
}
使用0.11.0版本thrift,在项目根目录生成package:
thrift -0 . -out commdef --gen go mydef.thrift
参考之前博客,编写server文件
首先,你会发现,好多地方编译不过,对比如下可用代码,进行说明:
// server.go
package main
import (
"context"
"fmt"
"thrifttest/commdef/mydef"
"os"
"git.apache.org/thrift.git/lib/go/thrift"
)
const (
NetWorkAddr = "127.0.0.1:9090"
)
type MyMathService struct {
mydef.MathService // <<< 这里
}
func (this *MyMathService) Add(ctx context.Context, A int32, B int32) (r int32, err error) { // <<< 这里
r = A + B
err = nil
fmt.Println("Add", A, B)
return
}
func main() {
handler := &MyMathService{}
processor := mydef.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()
}
type MyMathService struct {
这里,是之前就不妥,没有实现接口(类似继承)关系
func (this *MyMathService) Add(ctx context.Context, A int32, B int32) (r int32, err error) {
之前版本没有ctx相关内容,这里需要加上。
按照如上修改,仍然无法编译,错误是not enough arguments in call to oprot.Flush
, 这是thrift的go生成器的问题,没有添加对ctx的支持,我们手工找到,添加上。具体做法是将所有oprot.Flush()
替换为oprot.Flush(ctx)
。
最终,服务端可以正常运行。关键的修改都在于ctx的处理问题。
到这里你会发现,问题更严重,之前客户端的好多函数被声明取消,使用NewMathServiceClient
替代,这里经过查找api,替换函数,完毕。
然后,问题又来了,在client调用时,也需要提供ctx参数,我们没有,这里可以使用一个空的ctx占位,context.Background()
。
完整代码如下:
package main
import (
"context"
"thrifttest/commdef/mydef"
"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)
protocol := thrift.NewTBinaryProtocolTransport(client_transport)
client_t := thrift.NewTStandardClient(protocol,protocol)
client := mydef.NewMathServiceClient(client_t)
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(context.Background(),i, i)
fmt.Println(i, "Add", nRet)
}
fmt.Println("Over!")
}
服务器,客户端连接测试,完美!
这里出问题的ctx到底起什么作用呢?
建议多看看github上的issue,我了解到的大概意思是用来传递上下文环境,比如在http通信和普通通信时,添加额外参数,用来进行认证/校验…, 使用起来比较灵活,类似UI编程里面的UserData,以后遇到类似场景可以酌情使用。