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

    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

    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建立连接,传输编码后的请求参数,将参数解码后在本地找到对应函数,本地执行对应函数并填充回包,再把回包编码通过网络连接返回。即在网络连接上实现双方无感知调用对方函数。

    参考文件

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

相关推荐

  1. GOgrpc快速体验

    2024-02-09 12:36:01       19 阅读

最近更新

  1. TCP协议是安全的吗?

    2024-02-09 12:36:01       16 阅读
  2. 阿里云服务器执行yum,一直下载docker-ce-stable失败

    2024-02-09 12:36:01       16 阅读
  3. 【Python教程】压缩PDF文件大小

    2024-02-09 12:36:01       15 阅读
  4. 通过文章id递归查询所有评论(xml)

    2024-02-09 12:36:01       18 阅读

热门阅读

  1. Flutter typedef 函数类型

    2024-02-09 12:36:01       30 阅读
  2. 速盾:dns解析和cdn加速的区别与联系

    2024-02-09 12:36:01       34 阅读
  3. C++ [NOIP2007 提高组] 矩阵取数游戏

    2024-02-09 12:36:01       28 阅读
  4. lnmp指令

    2024-02-09 12:36:01       33 阅读
  5. C++中的递归算法

    2024-02-09 12:36:01       31 阅读
  6. 力扣刷题-392.判断子序列

    2024-02-09 12:36:01       26 阅读
  7. C语言中的作用域与生命周期

    2024-02-09 12:36:01       26 阅读
  8. 前端开发:(六)Vue快速入门

    2024-02-09 12:36:01       26 阅读
  9. GraphicsMagick 的 OpenCL 开发记录(三十四)

    2024-02-09 12:36:01       28 阅读
  10. c++学习:数组

    2024-02-09 12:36:01       25 阅读