gRPC快速入门

1 阅读3分钟

gRPC快速入门

前言

RPC--Remote Procedure Call的简称,中文叫远程过程调用,就是调用远程方法和调用本地方法一样

gRPC就是由google开发的一个高性能、通用的、可以跨语言的rpc框架。

环境准备

我是在windows环境配置的,所以会麻烦一点,以下的都需要安装

// 都需要安装的依赖
go get google.golang.org/grpc
go install google.golang.org/protobuf/cmd/protoc-gen-go@latest
go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest

许多人都卡在了这一步,因为涉及到一个环境变量的问题。

'protoc' 不是内部或外部命令,也不是可运行的程序
或批处理文件。

博主按照网上的教程重新配置了path 环境变量,并且 go env 查看也是正确,依然无法使用proto,使用winget命令下载

Windows, using Winget
> winget install protobuf
> protoc --version # Ensure compiler version is 3+

winget install protobuf
已找到 protobuf [Google.Protobuf] 版本 31.0
此应用程序由其所有者授权给你。
Microsoft 对第三方程序包概不负责,也不向第三方程序包授予任何许可证。
正在下载 https://github.com/protocolbuffers/protobuf/releases/download/v31.0/protoc-31.0-win64.zip
  ██████████████████████████████  3.21 MB / 3.21 MB
已成功验证安装程序哈希
正在提取存档...
已成功提取存档
正在启动程序包安装...
已修改路径环境变量;重启 shell 以使用新值。
添加了命令行别名: "protoc"
已成功安装

RPC demo 实践

我们需要实现两个服务,一个服务端一个客户端,来简单实现一个rpc的项目

编写服务端服务

package main

import (
  "fmt"
  "net"
  "net/http"
  "net/rpc"
)

type Server struct {
}
type Req struct {
  Num1 int
  Num2 int
}
type Res struct {
  Num int
}

func (s Server) Add(req Req, res *Res) error {
  res.Num = req.Num1 + req.Num2
  return nil
}

func main() {
  // 注册rpc服务
  rpc.Register(new(Server))
  rpc.HandleHTTP()
  listen, err := net.Listen("tcp", ":1019") //自定义
  if err != nil {
    fmt.Println(err)
    return
  }
  http.Serve(listen, nil)
}

编写客户端代码

package main

import (
  "fmt"
  "net/rpc"
)

type Req struct {
  Num1 int
  Num2 int
}
type Res struct {
  Num int
}

func main() {
  req := Req{1, 2}
  client, err := rpc.DialHTTP("tcp", ":1019")
  if err != nil {
    fmt.Println(err)
    return
  }
  var res Res
  client.Call("Server.Add", req, &res)
  fmt.Println(res)
}

最后分别打开两个终端运行即可。

hello_grpc

创建一个pb目录,在目录中创建一个hello_grpc.proto文件

syntax = "proto3"; // 指定proto版本
package hello_grpc;     // 指定默认包名

// 指定golang包名
option go_package="./;hello_grpc";

//定义rpc服务
service HelloService  {
  // 定义函数
  rpc SayH (Req ) returns (Res) {}
}

// HelloRequest 请求内容
message Req {
  string message = 1;
}

// HelloResponse 响应内容
message Res{
  string message = 1;
}

编写转换命令,这里建议使用.bat执行,可以方便点。

protoc --go_out=. --go_opt=paths=source_relative --go-grpc_out=. --go-grpc_opt=paths=source_relative ./hello_grpc.proto

运行.bat 可能会出现这个报错,这是你缺少了指定go的包名而出现的问题

E:\GoProject\src\rpc_demo\pb>protoc --go_out=. --go_opt=paths=source_relative --go-grpc_out=. --go-grpc_opt=paths=source_relative ./hello_grpc.proto

protoc-gen-go: unable to determine Go import path for "hello_grpc.proto"

Please specify either:

  • a "go_package" option in the .proto source file, or

  • a "M" argument on the command line.

See [https://protobuf.dev/reference/go/go-generated#package](https://protobuf.dev/reference/go/go-generated#package) for more information.

--go_out: protoc-gen-go: Plugin failed with status code 1.
option go_package="./;hello_grpc";

服务端

  1. 取出server
type server struct {
hello_grpc.UnimplementedHelloGRPCServer
}
  1. 挂载方法
func (s *server) SayHi(ctx context.Context,req *hello_grpc.Req) (res *hello_grpc.Res, err error) {
fmt.Println(req.GetMessage())
return &hello_grpc.Res{Message: "我是从服务端返回的grpc的内容"},nil
}
  1. 注册服务
l,_ := net.Listen("tcp",":1019")
s:=grpc.NewServer()
hello_grpc.RegisterHelloGRPCServer(s,&server{})

  1. 创建监听
s.Serve(l)

客户端

  1. 创建一个连接
  2. new 一个client 对象
  3. 调用client的方法
  4. 获取返回值
func main() {
  addr := ":1019"
  //创建一个连接
  conn, err := grpc.Dial(addr, grpc.WithTransportCredentials(insecure.NewCredentials()))
  if err != nil {
    log.Fatalf(fmt.Sprintf("grpc connect addr [%s] 连接失败 %s", addr, err))
  }
  defer conn.Close()
  //new 一个clint
  client := hello_grpc.NewHelloServiceClient(conn)
  result, err := client.SayHi(context.Background(), &hello_grpc.Req{
   Message: "ok",
  })
  fmt.Println(result, err)
}