引言
在 Go原生方法实现RPC 文章中,我们通过原生的方法实现了 RPC 调用。但是大多是基于 protobuf 进行 RPC 的实现。
gRPC是Google公司基于Protobuf开发的跨语言的开源RPC框架。gRPC基于HTTP/2协议设计,可以基于一个HTTP/2链接提供多个服务,对于移动设备更加友好。本节将讲述gRPC的简单用法。
gRPC技术栈:
最底层为TCP或Unix Socket协议,在此之上是HTTP/2协议的实现,然后在HTTP/2协议之上又构建了针对Go语言的gRPC核心库。应用程序通过gRPC插件生产的Stub代码和gRPC核心库通信,也可以直接和gRPC核心库通信。
参考文献
protobuf入门学习:https://github.com/mailjobblog/dev_go/tree/master/220115_protobuf
Go原生RPC+protobuf代码下载:https://github.com/mailjobblog/dev_go/tree/master/220113_rpc/3.rpc_protobuf
gRPC代码下载:https://github.com/mailjobblog/dev_go/tree/master/220113_rpc/4.grpc
RPC实现
Go原生rpc+proto实现
代码实现
hello.proto
syntax = "proto3";
package pb;
option go_package="./pb;pb";
// 请求结构体
message HelloRequest {
string res = 1;
}
// 返回结构体
message HelloResponse {
int64 reply = 1;
}
server.go
func main() {
rpc.Register(new(HelloService))
listener, err := net.Listen("tcp", ":8888")
if err != nil {
log.Fatal("ListenTCP error:", err)
}
for {
conn, err := listener.Accept()
if err != nil {
log.Fatal("Accept error:", err)
}
go rpc.ServeConn(conn)
}
}
type HelloService struct{}
// Length 和原生相比,这里的接收参数和返回参数都用的是proto生成的代码
func (h *HelloService) Length(res pb.HelloRequest, reply *pb.HelloResponse) error {
reply.Reply = int64(len(res.Res))
return nil
}
client_test.go
func TestClient(t *testing.T) {
client, err := rpc.Dial("tcp", "127.0.0.1:8888")
if err != nil {
log.Fatal("dialing:", err)
}
// 定义请求和接受参数
// 接收参数和返回参数都用的是proto生成的代码
res := pb.HelloRequest{Res: "test666"}
var reply pb.HelloResponse
err = client.Call("HelloService.Length", res, &reply)
if err != nil {
log.Fatal(err)
}
fmt.Println(reply)
}
gRPC实现
代码实现
hello.proto
syntax = "proto3";
package pb;
option go_package="./pb;pb";
// 请求结构体
message HelloRequest {
string res = 1;
}
// 返回结构体
message HelloResponse {
int64 reply = 1;
}
// GRPC服务
service HelloService {
// 计算字符串长度
rpc Length(HelloRequest) returns (HelloResponse);
}
server.go
func main() {
// 创建一个 grpc server
grpcServer := grpc.NewServer()
// 注册 grpc
pb.RegisterHelloServiceServer(grpcServer, new(HelloService))
lis, err := net.Listen("tcp", ":8888")
if err != nil {
log.Fatal(err)
}
// 监听端口上提供gRPC服务
grpcServer.Serve(lis)
}
type HelloService struct {
pb.UnimplementedHelloServiceServer
}
func (h *HelloService) Length(ctx context.Context, res *pb.HelloRequest) (*pb.HelloResponse, error) {
reply := &pb.HelloResponse{Reply: int64(len(res.Res))}
return reply, nil
}
client_test.go
func TestClient(t *testing.T) {
conn, err := grpc.Dial("127.0.0.1:8888", grpc.WithTransportCredentials(insecure.NewCredentials()))
if err != nil {
log.Fatal(err)
}
defer conn.Close()
client := pb.NewHelloServiceClient(conn)
reply, err := client.Length(context.Background(), &pb.HelloRequest{Res: "test123456"})
if err != nil {
log.Fatal(err)
}
fmt.Println(reply.Reply)
fmt.Println(reply.GetReply())
}