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";
服务端
- 取出server
type server struct {
hello_grpc.UnimplementedHelloGRPCServer
}
- 挂载方法
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
}
- 注册服务
l,_ := net.Listen("tcp",":1019")
s:=grpc.NewServer()
hello_grpc.RegisterHelloGRPCServer(s,&server{})
- 创建监听
s.Serve(l)
客户端
- 创建一个连接
- new 一个client 对象
- 调用client的方法
- 获取返回值
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)
}