Window环境下使用go编译grpc最新教程

网上的grpc教程都或多或少有些老或者有些问题,导致最后执行生成文件时会报很多错。这里给出个人实践出可执行的编译命令与碰到的报错与解决方法。(ps:本文代码按照煎鱼的教程编写:4.2 gRPC Client and Server - 跟煎鱼学 Go (gitbook.io)

最后看了官网,果然只有官网的教程不会太老导致不可用。

  • 项目目录结构

    grpc_test
    ├─client
    | └─main
    | └─client.go
    └─proto
    | |─grpc
    | └─search.proto
    └─server
    └─main
    └─server.go

  • 下载protoc不做介绍请自行下载

    下载后执行protoc --version

    输出类似以下信息则安装成功,否则卸载重新安装

    复制代码
    libprotoc 25.1
  • 下载go编译proto插件

    下面的命令已废弃!不要使用

    复制代码
    go get -u github.com/golang/protobuf/protoc-gen-go

    请使用下面命令!

    复制代码
    go get -u google.golang.org/grpc
    go install google.golang.org/protobuf/cmd/protoc-gen-go
    go install google.golang.org/grpc/cmd/protoc-gen-go-grpc

    观察GOPATH目录的bin下有两个文件

  • 编写search.proto文件

    复制代码
    syntax = "proto3";
    
    package proto;
    
    service SearchService {
        rpc Search(SearchRequest) returns (SearchResponse) {}
    }
    
    message SearchRequest {
        string request = 1;
    }
    
    message SearchResponse {
        string response = 1;
    }
  • 执行编译命令

    复制代码
    $ protoc --go_out=plugins=grpc:. *.proto

以上是煎鱼的grpc教程,可能由于版本或者环境导致现在并不能使用了,下面列出我遇到的报错以及如何解决

  • 报错一:插件旧库已废弃,且安装新库命令由于本地go tool版本不匹配安装失败

    执行下面命令报错该库已经废弃

    复制代码
    go get -u github.com/golang/protobuf/protoc-gen-go

    执行下面命令时报错tool的版本不对

    复制代码
    go install google.golang.org/protobuf/cmd/protoc-gen-go

    报错信息

    复制代码
    compile: version "go1.20.13" does not match go tool version "go1.21.6"

    该报错导致插件下载失败,网上说是升级版本时以前的库没删干净,但是我并没用找到以前的库。所以我全部重新安装了最近的1.22

    • 首先把GOPATH下三个文件夹里文件全部删除

    • 把GOROOT里文件全部删除

    • 去官网重新下载Windows版本的1.22的zip文件解压到我的GOROOT里(ps:安装新版本后本地执行go version可能还是以前的版本,不用担心,这是本地环境的缓存,重启一下再go version就好,就像linux里修改环境文件都要sourse一下才能使用)

      重新执行插件安装命令,执行成功!

  • 报错二:执行编译命令失败

    执行下面编译命令时报错

    复制代码
    $ protoc --go_out=plugins=grpc:. *.proto

    报错

    复制代码
    'protoc-gen-go' 不是内部或外部命令,也不是可运行的程序
    或批处理文件。
    --go_out: protoc-gen-go: Plugin failed with status code 1.

    原因:该命令不可用或者本地插件环境未配置好

    下面把GOPATH的bin目录下新下载的文件安装到GOROOT下bin中解决!

    我本地GOROOT的文件夹是go

  • 报错三:输出参数不对

    复制代码
    --proto_path passed empty directory name.  (Use "." for current directory.)

    这是proto3后来规定文件中必须要配置go_package参数,在文件中配置加上此参数以解决(protoc 3.10 版本后可能会报此错误)

    复制代码
    syntax = "proto3";
    
    package proto;
    
    option go_package = "/grpc;proto";
    
    service SearchService {
        rpc Search(SearchRequest) returns (SearchResponse) {}
    }
    
    message SearchRequest {
        string request = 1;
    }
    
    message SearchResponse {
        string response = 1;
    }

    option go_package = "/grpc;proto";

    分号前是输出的 .pb.go 文件的路径,路径不存在会自动创建

    分号后是输入的 .pb.go 文件的包名

    最后进入proto目录并执行下面命令,grpc目录下会自动生成编译文件(ps:grpc目录自己创建,不建议生成编译go文件在proto中,因为grpc的缺陷是后面修改proto文件都需要重新编译生成go文件,若proto文件写错了会覆盖原来好的文件。建议生成在别的目录下确认不误后再投入使用)

    另外煎鱼的教程可能版本只能生成一个go文件,代码也不对了。请使用下面命令!

    复制代码
    protoc --go_out=. --go-grpc_out=. search.proto
    • 煎鱼的代码可能也是不能用了,我重写了一下,加上timeoutcontext的超时关闭逻辑,测试后可以正常运行

    client.go

    go 复制代码
    package main
    
    import (
    	"context"
    	"fmt"
    	"log"
    	"time"
    
    	"google.golang.org/grpc"
    	"google.golang.org/grpc/credentials/insecure"
    
    	pb "grpc_test/proto/grpc"
    	proto "grpc_test/proto/grpc"
    )
    
    const address = "127.0.0.1:9001"
    
    func getGrpcConn(address string) (*grpc.ClientConn, *proto.SearchServiceClient, *context.CancelFunc, error) {
    	ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
    	// timeoutcontex用于超时自动关闭
    	// grpc.WithBlock()用于配置gRPC客户端连接阻塞并等待连接建立或失败后再返回
    	// 在需要确保连接就绪后再继续执行后续代码的场景中很有用
    	// grpc现在强制要求设置TLS,withinsurance已经废弃
    	conn, err := grpc.DialContext(ctx, address, grpc.WithBlock(), grpc.WithTransportCredentials(insecure.NewCredentials()))
    	if err != nil {
    		msg := fmt.Sprintf("did not connect to %v error %v", address, err)
    		log.Println(msg)
    	}
    	client := proto.NewSearchServiceClient(conn)
    	return conn, &client, &cancel, err
    }
    
    func main() {
    
    	conn, client, _, _ := getGrpcConn(address)
    	defer conn.Close()
    	// Contact the server and print out its response.
    	ctx, cancel := context.WithTimeout(context.Background(), time.Second)
    	defer cancel()
    	// 使用服务端函数
    	resp, err := (*client).Search(ctx, &pb.SearchRequest{Request: "gRPC"})
    	if err != nil {
    		log.Fatalf("client.Search err: %v", err)
    	}
    
    	log.Printf("resp: %s", resp.GetResponse())
    }

    server.go

    go 复制代码
    package main
    
    import (
    	"context"
    	"fmt"
    	"log"
    	"net"
    
    	"google.golang.org/grpc"
    
    	pb "grpc_test/proto/grpc"
    
    )
    
    type SearchService struct {
    	pb.UnimplementedSearchServiceServer
    }
    
    func (s *SearchService) Search(ctx context.Context, r *pb.SearchRequest) (*pb.SearchResponse, error) {
    	fmt.Println("sever serching")
    	return &pb.SearchResponse{Response: r.GetRequest() + " Server"}, nil
    }
    
    const PORT = "9001"
    
    func main() {
    	// 获取grpc服务端(被调用方)
    	server := grpc.NewServer()
    	// 服务端映射到结构体SearchService{}(注册)
    	pb.RegisterSearchServiceServer(server, &SearchService{})
    	// 建立tcp端口监听
    	lis, err := net.Listen("tcp", ":"+PORT)
    	if err != nil {
    		log.Fatalf("net.Listen err: %v", err)
    	}
    	// 服务端监听tcp连接
    	if err := server.Serve(lis); err != nil {
    		log.Fatalf("net.Listen err: %v", err)
    	}
    }

    有兴趣的可以看看rpc的设计原理,其实大多应用在使用时就可以反映出大致原理,rpc的设计框架也是,从网络传输协议,序列化协议,消息编码协议三层设计,另外加上函数注册和参数注册的逻辑。利用tcp或者http建立连接,传输编码后的请求参数,将参数解码后在本地找到对应函数,本地执行对应函数并填充回包,再把回包编码通过网络连接返回。即在网络连接上实现双方无感知调用对方函数。

    参考文件

    记不得了,全网教程几乎都看了,参考太多了

相关推荐
duapple2 小时前
Golang基于反射的ioctl实现
开发语言·后端·golang
Dxy12393102162 小时前
Python 条件语句详解
开发语言·python
prinrf('千寻)5 小时前
MyBatis-Plus 的 updateById 方法不更新 null 值属性的问题
java·开发语言·mybatis
m0_555762905 小时前
Qt缓动曲线详解
开发语言·qt
my_styles5 小时前
docker-compose部署项目(springboot服务)以及基础环境(mysql、redis等)ruoyi-ry
spring boot·redis·后端·mysql·spring cloud·docker·容器
飞川撸码5 小时前
【LeetCode 热题100】739:每日温度(详细解析)(Go语言版)
算法·leetcode·golang
揽你·入怀6 小时前
数据结构:ArrayList简单实现与常见操作实例详解
java·开发语言
AA-代码批发V哥6 小时前
Math工具类全面指南
java·开发语言·数学建模
Nobkins6 小时前
2021ICPC四川省赛个人补题ABDHKLM
开发语言·数据结构·c++·算法·图论
十八年的好汉6 小时前
buck变换器的simulink/matlab仿真和python参数设计
开发语言·matlab