匠心精神 - 良心品质腾讯认可的专业机构-IT人的高薪实战学院

咨询电话:4000806560

【实践】goland中使用protobuf实现高效率的RPC调用

【实践】goland中使用protobuf实现高效率的RPC调用

近年来,随着分布式系统和微服务的普及,RPC(远程过程调用)作为一种高效、方便的通信方式开始被广泛应用。其中,Google的protobuf作为一种高效的序列化工具,受到了广泛的青睐。本文将结合goland开发环境,讲解如何使用protobuf实现高效率的RPC调用。

1. 安装protobuf

首先,我们需要安装protobuf的编译器,可以通过以下命令来安装:

```
$ sudo apt-get install protobuf-compiler
```

安装完成后,我们需要下载protobuf的golang插件,可以通过以下命令来安装:

```
$ go get -u github.com/golang/protobuf/{proto,protoc-gen-go}
```

2. 编写.proto文件

在使用protobuf进行RPC调用时,我们需要先定义一个.proto文件,来描述我们要传输的数据格式。下面,我们以一个简单的demo为例,来说明.proto文件的编写。

在项目根目录下创建proto文件夹,并在其中创建hello.proto文件,写入以下内容:

```
syntax = "proto3";

package hello;

message Request {
  string name = 1;
}

message Response {
  string greeting = 1;
}

service Greeter {
  rpc SayHello(Request) returns (Response);
}
```

通过上述代码,我们定义了一个hello.proto文件,其中:

- syntax = "proto3":指定使用protobuf的版本为3;
- package hello:指定package的名称;
- message Request:定义了Request包含一个string类型的参数;
- message Response:定义了Response包含一个string类型的参数;
- service Greeter:定义了一个服务,包含一个SayHello方法,入参为Request,出参为Response。

3. 编译.proto文件

我们需要使用protobuf的编译器来编译.proto文件,生成相应的go文件。在项目根目录下执行以下命令:

```
$ protoc --go_out=plugins=grpc:. proto/*.proto
```

执行完成后,我们可以看到在proto文件夹下生成了与.proto文件同名的go文件。

4. 创建服务端

下面,我们将通过golang在服务端实现一个简单的RPC调用。在项目根目录下创建server.go文件,写入以下代码:

```
package main

import (
	"context"
	"log"
	"net"

	pb "github.com/your/path/proto" // 引入proto生成的go文件
	"google.golang.org/grpc"
)

const (
	port = ":50051" // 服务端口号
)

// server is used to create the hello service.
type server struct{}

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

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{})
	log.Printf("Server listening at %v", lis.Addr())
	if err := s.Serve(lis); err != nil {
		log.Fatalf("failed to serve: %v", err)
	}
}
```

通过上述代码,我们创建了一个服务端,其中:

- 引入proto生成的go文件:通过import语句引入生成的go文件;
- SayHello方法:用于处理客户端的请求,将客户端传来的名字与“Hello ”进行拼接并返回;
- main函数:创建一个监听端口,并启动服务。

5. 创建客户端

下面,我们将通过golang在客户端实现一个简单的RPC调用。在项目根目录下创建client.go文件,写入以下代码:

```
package main

import (
	"context"
	"log"
	"os"
	"time"

	pb "github.com/your/path/proto" // 引入proto生成的go文件
	"google.golang.org/grpc"
)

const (
	address     = "localhost:50051" // 服务端地址
	defaultName = "world"
)

func main() {
	// 建立连接
	conn, err := grpc.Dial(address, grpc.WithInsecure(), grpc.WithBlock())
	if err != nil {
		log.Fatalf("did not connect: %v", err)
	}
	defer conn.Close()
	c := pb.NewGreeterClient(conn)

	// 创建请求
	name := defaultName
	if len(os.Args) > 1 {
		name = os.Args[1]
	}
	ctx, cancel := context.WithTimeout(context.Background(), time.Second)
	defer cancel()
	r, err := c.SayHello(ctx, &pb.Request{Name: name})
	if err != nil {
		log.Fatalf("could not greet: %v", err)
	}
	log.Printf("Greeting: %s", r.GetGreeting())
}
```

通过上述代码,我们创建了一个客户端,其中:

- 引入proto生成的go文件:通过import语句引入生成的go文件;
- 建立连接:使用grpc.Dial函数连接服务端;
- 创建请求:创建一个携带name参数的Request,向服务端发送请求,并等待返回结果;
- 输出结果:输出服务端返回的结果。

6. 运行程序

在完成服务端和客户端的编写后,我们需要在终端窗口中分别运行server.go和client.go,即可看到以下输出结果:

服务端输出:

```
2021/10/16 17:07:56 Server listening at localhost:50051
2021/10/16 17:08:04 Received: world
```

客户端输出:

```
2021/10/16 17:08:04 Greeting: Hello world
```

通过上述输出结果,我们可以看到,使用protobuf实现RPC调用,可以实现高效率的数据传输,并且使用简单、方便。在实际应用中,我们可以根据.proto文件定义数据结构,并通过golang快速实现服务和客户端,实现高效率的分布式系统。