Golang实现grpc server和grpc client(protobuf格式消息通信)介绍教程

栏目: 服务器 · 发布时间: 7年前

内容简介:下面使用的例子是先安装需要的工具、下载代码,后面再分析是怎样做的。安装protobuf compile,安装以后,本地会有一个

说明

下面使用的例子是 grpc-go 中的 gRPC in 3 minutes (Go) ,没有将完整的代码复制粘贴到这里,只截取了一些代码片段。

生成定义文件

先安装需要的 工具 、下载代码,后面再分析是怎样做的。

安装protobuf compile,安装以后,本地会有一个 protoc 命令可用,在mac上可以直接用brew安装:

$ brew install protobuf

安装protobuf的 go 代码生成工具,确保 protoc-gen-go 命令存在:

$ go get -u github.com/golang/protobuf/protoc-gen-go
$ which protoc-gen-go
/Users/lijiao/Work/Bin/gopath/bin/protoc-gen-go

下载示例代码,分为client和server两部分:

$ go get -u google.golang.org/grpc/examples/helloworld/greeter_client
$ go get -u google.golang.org/grpc/examples/helloworld/greeter_server
$ cd $GOPATH/src/google.golang.org/grpc/examples/helloworld

helloworld/helloworld.proto 是用grpc的语法定义的消息格式,这个文件无法被直接使用的,需要转成对应语言的文件。

generate命令在 greeter_server/main.go 中:

$ grep -R -n "//go:generate" .
./greeter_server/main.go:19://go:generate protoc -I ../helloworld --go_out=plugins=grpc:../helloworld ../helloworld/helloworld.proto

greeter_server/main.go 中的 go:generate 命令,会被 go generate 命令执行,生成 helloworld.proto 的go语言定义文件:

$ go generate google.golang.org/grpc/examples/helloworld/...
$ ls helloworld
helloworld.pb.go helloworld.proto

helloworld/helloworld.pb.go 是生成的go文件,可以被引用、使用。

消息格式:.proto文件

.proto文件中定义了grpc通信的消息格式和接口,以 helloworld/helloworld.proto 为例:

syntax = "proto3";

option java_multiple_files = true;
option java_package = "io.grpc.examples.helloworld";
option java_outer_classname = "HelloWorldProto";

package helloworld;

// The greeting service definition.
service Greeter {
  // Sends a greeting
  rpc SayHello (HelloRequest) returns (HelloReply) {}
}

// The request message containing the user's name.
message HelloRequest {
  string name = 1;
}

// The response message containing the greetings
message HelloReply {
  string message = 1;
}

.proto文件中定义的是protobuf格式的消息,定义语法可以在 Language Guide (proto3) 中看到。

这里的.proto中定义了一个名为 SayHello 的接口,并且定义了这个接口接收的消息格式 HelloRequest 和返回的消息格式 HelloReply

.proto文件中的内容都会在生成的.pb.go文件中体现出来。例如:

type HelloRequest struct {
    Name                 string   `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
    XXX_NoUnkeyedLiteral struct{} `json:"-"`
    XXX_unrecognized     []byte   `json:"-"`
    XXX_sizecache        int32    `json:"-"`
}
...
type GreeterClient interface {
    // Sends a greeting
    SayHello(ctx context.Context, in *HelloRequest, opts ...grpc.CallOption) (*HelloReply, error)
}
type GreeterServer interface {
    // Sends a greeting
    SayHello(context.Context, *HelloRequest) (*HelloReply, error)
}
...

服务端:grpc server

Go提供了 package grpc ,服务端和客户端的开发都可以考虑使用这个包。

import "google.golang.org/grpc"

Package grpc implements an RPC system called gRPC.

See grpc.io for more information about gRPC.

使用protobuf协议的接口已经在前面的.proto文件中定义了,并且在.pb.go文件中生成对应的interface定义:

// GreeterServer is the server API for Greeter service.
type GreeterServer interface {
	// Sends a greeting
	SayHello(context.Context, *HelloRequest) (*HelloReply, error)
}

服务端首先需要做的实现这些接口,例如 greeter_server/main.go 的server:

package main

import (
	...
	pb "google.golang.org/grpc/examples/helloworld/helloworld"
	...
)

// server is used to implement helloworld.GreeterServer.
type server struct{}

// SayHello implements helloworld.GreeterServer
func (s *server) SayHello(ctx context.Context, in *pb.HelloRequest) (*pb.HelloReply, error) {
	log.Printf("Received: %v", in.Name)
	return &pb.HelloReply{Message: "Hello " + in.Name}, nil
}

注意接口第二个输入参数类型是 *pb.HelloRequest ,它是在生成的pb.go文件中定义的,是接口接收的消息。

然后创建grpc server,并将实现了接口的struct注入:

func main() {
	lis, err := net.Listen("tcp", port)
	if err != nil {
		log.Fatalf("failed to listen: %v", err)
	}
	s := grpc.NewServer()
	pb.RegisterGreeterServer(s, &server{})
	// Register reflection service on gRPC server.
	reflection.Register(s)
	if err := s.Serve(lis); err != nil {
		log.Fatalf("failed to serve: %v", err)
	}
}

注册函数 pb.RegisterGreeterServer 也是在pb.go文件中定义的,是自动生成的。所以需要做的事情,就是创建lis,启动grpc server等很简单工作。

客户端:grpc client

客户端的更简单,建立grpc连接,然后直接调用接口就可以了。

建立grpc连接,创建对应的client:

	conn, err := grpc.Dial(address, grpc.WithInsecure())
	if err != nil {
		log.Fatalf("did not connect: %v", err)
	}
	defer conn.Close()
	c := pb.NewGreeterClient(conn)

创建client的 pb.NewGreeterClient() 函数也是在.pb.go中定义的,自动生成的。

剩下的工作就是直接调用client的接口:

	ctx, cancel := context.WithTimeout(context.Background(), time.Second)
	defer cancel()
	r, err := c.SayHello(ctx, &pb.HelloRequest{Name: name})
	if err != nil {
		log.Fatalf("could not greet: %v", err)
	}
	log.Printf("Greeting: %s", r.Message)

c.SayHello() 的第二个参数就是要发送的数据,第一个参数是go标准库中的context,可以用来传递数据。

怎样找到grpc实现的接口?

如果一套grpc server代码是其他人实现的,并且.proto文件分散到了各个地方,这时候要怎样知道server实现了哪些接口?

可以在 ResiterXXX 方法中找到:

	pb.RegisterGreeterServer(s, &server{})

RegisterGreeterServer() 的实现:

func RegisterGreeterServer(s *grpc.Server, srv GreeterServer) {
    s.RegisterService(&_Greeter_serviceDesc, srv)
}

_Greeter_serviceDesc 对这个接口的描述是完整的,包含了所有支持的方法:

var _Greeter_serviceDesc = grpc.ServiceDesc{
    ServiceName: "helloworld.Greeter",
    HandlerType: (*GreeterServer)(nil),
    Methods: []grpc.MethodDesc{
        {
            MethodName: "SayHello",
            Handler:    _Greeter_SayHello_Handler,
        },
    },
    Streams:  []grpc.StreamDesc{},
    Metadata: "helloworld.proto",
}

另一种方法是找到 RegisterGreeterServer() 对应的Client创建函数,这里是 NewGreeterClient() ,它们在同一个.pb.go文件中。

func NewGreeterClient(cc *grpc.ClientConn) GreeterClient {
    return &greeterClient{cc}
}

NewGreeterClient() 返回的类型的方法就是可以调用的方法:

+GreeterClient : interface
    [methods]
   +SayHello(ctx context.Context, in *HelloRequest, opts ...grpc.CallOption) : *HelloReply, error

参考

  1. gRPC in 3 minutes (Go)
  2. package grpc
  3. GRPC Go Quick Start
  4. Language Guide (proto3)

以上所述就是小编给大家介绍的《Golang实现grpc server和grpc client(protobuf格式消息通信)介绍教程》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

The Shallows

The Shallows

Nicholas Carr / W. W. Norton & Company / 2010-6-15 / USD 26.95

"Is Google making us stupid?" When Nicholas Carr posed that question, in a celebrated Atlantic Monthly cover story, he tapped into a well of anxiety about how the Internet is changing us. He also crys......一起来看看 《The Shallows》 这本书的介绍吧!

JSON 在线解析
JSON 在线解析

在线 JSON 格式化工具

MD5 加密
MD5 加密

MD5 加密工具

HEX HSV 转换工具
HEX HSV 转换工具

HEX HSV 互换工具