Go语言入门学习--进阶篇gRPC

一.gRPC简介 gRPC和RPC区别

在 gRPC 里客户端应用可以像调用本地对象一样直接调用另一台不同的机器上服务端应用的方法,使得您能够更容易地创建分布式应用和服务。与许多 RPC 系统类似,gRPC 也是基于以下理念:定义一个服务,指定其能够被远程调用的方法(包含参数和返回类型)。在服务端实现这个接口,并运行一个 gRPC 服务器来处理客户端调用。在客户端拥有一个存根能够像服务端一样的方法。

gRPC  是一个高性能、开源和通用的 RPC 框架,面向移动和 HTTP/2 设计。目前提供 C、Java 和 Go 语言版本,分别是:grpc, grpc-java, grpc-go. 其中 C 版本支持 C, C++, Node.js, Python, Ruby, Objective-C, PHP 和 C# 支持.

gRPC 基于 HTTP/2 标准设计,带来诸如双向流、流控、头部压缩、单 TCP 连接上的多复用请求等特。这些特性使得其在移动设备上表现更好,更省电和节省空间占用。

https://www.grpc.io/img/grpc_concept_diagram_00.png

二.搭建本地环境

安装go语言并配置环境变量

2.1配置Protoc可执行文件

下载地址https://github.com/protocolbuffers/protobuf/releases/download/v3.6.0/protoc-3.6.0-win32.zip

把这么文件里面的bin里面的protoc.exe 复制到GOPATH/bin下,GOPATH/bin加入环境变量。也可以放到C:\windows\System32文件夹下。

2.2获取protobuf的编译器插件 protoc-gen-go

go get -u github.com/golang/protobuf/protoc-gen-go

2.3    安装gRPC

a.能够访问谷歌可以直接运行

go get -u google.golang.org/grpc

b. 从github上克隆grpc的依赖库到GOPATH目录

编译安装gRPC

git clone https://github.com/grpc/grpc-go.git $GOPATH/src/google.golang.org/grpc

git clone https://github.com/golang/net.git          $GOPATH/src/golang.org/x/net

git clone https://github.com/golang/text.git         $GOPATH/src/golang.org/x/text

git clone https://github.com/google/go-genproto.git  $GOPATH/src/google.golang.org/genproto

cd $GOPATH/src/

go install google.golang.org/grpc

2.4安装IDE相应的插件

file->Settings->Plugins->Browse repositories->输入protobuf support->install

 

三.Protobuf

3.1什么是Protobuf

gRPC 默认使用 protocol buffers,这是 Google 开源的一套成熟的结构数据序列化机制(当然也可以使用其他数据格式如 JSON)。

Protobuf全称是Google Protocol Buffer,是一种高效轻便的结构化数据存储方式,可用于(数据)通信协议、数据存储等。
也可以理解为结构化数据的序列化方法,可简单类比为XML(这里主要是指在数据通信和数据存储这些应用场景中序列化方面的类比),其具有以下特点:

  • 语言无关,平台无关
    Protobuf支持Java, C++, Python,Go等多种语言,支持多个平台。
  • 高效
    比XML更小(3~10倍),更快(20 ~ 100倍),更为简单。
  • 扩展性,兼容性好
    可以更新数据结构,而不影响和破坏原有的旧程序。

3.2定义一个.proto文件

proto3代表该文件采用的规范

HelloRequest是定义的结构体,用于传递数据

syntax = "proto3";

  

package hello;

  

service Hello{

    rpc SayHello (HelloRequest) returns (HelloReply) {}

}

  

message HelloRequest {

    string name = 1;

}

  

message HelloReply {

    string message = 1;

}

3.3将.proto文件转换为go文件

.proto文件无法直接被变成语言直接调用,需要转换为相应语言的文件供编程语言调用

protoc --go_out=plugins=grpc:. hello.proto

运行完成后可以生成相应的文件test.pb.go,该文件是可以被go语言直接使用的。

四.gRPC使用

4.1创建server端

package main

  import (

   "context"

   "log"

   "net"

   pb "grpcpro/protoc"

  

   "google.golang.org/grpc"

  )

  

  const (

   addr = "127.0.0.1:50052"

  )

  

  type server struct{}

  

  func (s *server) SayHello(ctx context.Context, in *pb.HelloRequest) (*pb.HelloReply, error) {

   log.Printf("Received: %v", in.Name)

   return &pb.HelloReply{Message: "Hello " + in.Name}, nil

  }

  func main() {

   s := grpc.NewServer()

   pb.RegisterHelloServer(s, &server{})

  

   lis, err := net.Listen("tcp", addr)

   if err != nil {

      log.Fatalf("failed to listen: %v", err)

   }

   if err := s.Serve(lis); err != nil {

      log.Fatalf("failed to serve: %v", err)

   }

}

4.2创建client端

package main

  

  import (

   "context"

   "log"

   "os"

   "time"

   pb "grpcpro/protoc"

   "google.golang.org/grpc"

  )

  

  const (

   address     = "127.0.0.1:50052"

   defaultName = "world"

  )

  

  func main() {

  

  

   // grpc.Dial负责和GRPC服务建立链接

   conn, err := grpc.Dial(address, grpc.WithInsecure())

   if err != nil {

      log.Fatalf("did not connect: %v", err)

   }

   defer conn.Close()

   // 然后NewGreeterClient函数基于已经建立的链接构造GreeterClient对象

   // 返回的client其实是一个GreeterClient接口对象,通过接口定义的方法就可以调用服务端对应的GRPC服务提供的方法。

   c := pb.NewHelloClient(conn)

  

   // client第一个参数作为name的输入

   name := defaultName

   if len(os.Args) > 1 {

      name = os.Args[1]

   }

   //5秒超时

   ctx, cancel := context.WithTimeout(context.Background(), time.Second*5)

   defer cancel()

   r, err := c.SayHello(ctx, &pb.HelloRequest{Name: name})

   if err != nil {

      log.Fatalf("could not greet: %v", err)

   }

   log.Printf("Hello: %s", r.Message)

}

 

编译执行文件后可获得如下输出

go build

./server

./client hihi

./client hihi

server提示:2019/11/29 14:36:51 Received: hihi

client提示:2019/11/29 14:37:02 Hello: Hello hihi

4.3gRPC证书认证使用

Server端改造

使用http的http.ListenAndServeTLS代替net.Listen

package main

  import (

   "context"

   "log"

   "net/http"

   pb "grpcpro/protoc"

   "google.golang.org/grpc"

  )

  

  const (

   addr = "127.0.0.1:50052"

  )

  

  type server struct{}

  

  func (s *server) SayHello(ctx context.Context, in *pb.HelloRequest) (*pb.HelloReply, error) {

   log.Printf("Received: %v", in.Name)

   return &pb.HelloReply{Message: "Hello " + in.Name}, nil

  }

  

  func main() {

   s := grpc.NewServer()

   // var size = 1024 * 1024 * 1024 //1024M

   // s := grpc.NewServer(grpc.MaxMsgSize(size), grpc.MaxRecvMsgSize(size), grpc.MaxSendMsgSize(size))

   pb.RegisterHelloServer(s, &server{})

   if err:=http.ListenAndServeTLS(addr, "../cert/server.crt", "../cert/server.key",

      http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {

         s.ServeHTTP(w, r) // GRPC Server

         return

      }),

   );err!=nil{

      panic(err)

   }

}

Client端改造

client应该使用生成的client证书,在客户端就基于CA证书对服务器进行证书验证

package main

  

  import (

   "context"

   "log"

   "os"

   "time"

   "crypto/x509"

   "crypto/tls"

   "io/ioutil"

   "google.golang.org/grpc/credentials"

   pb "grpcpro/protoc"

   "google.golang.org/grpc"

  )

  

  const (

   address     = "127.0.0.1:50052"

   defaultName = "world"

  )

  

  func main() {

  

   certificate, err := tls.LoadX509KeyPair("../cert/client.crt", "../cert/client.key")

   if err != nil {

      log.Fatal(err)

   }

  

   certPool := x509.NewCertPool()

   ca, err := ioutil.ReadFile("../cert/ca.crt")

   if err != nil {

      log.Fatal(err)

   }

   if ok := certPool.AppendCertsFromPEM(ca); !ok {

      log.Fatal("failed to append ca certs")

   }

   creds := credentials.NewTLS(&tls.Config{

      Certificates: []tls.Certificate{certificate},

      ServerName: "grpcpro1", // NOTE: this is required!

      RootCAs: certPool,

   })

  

  

  

   // grpc.Dial负责和GRPC服务建立链接

   conn, err := grpc.Dial(address, grpc.WithTransportCredentials(creds))

   if err != nil {

      log.Fatalf("did not connect: %v", err)

   }

   defer conn.Close()

   // 然后NewGreeterClient函数基于已经建立的链接构造GreeterClient对象

   // 返回的client其实是一个GreeterClient接口对象,通过接口定义的方法就可以调用服务端对应的GRPC服务提供的方法。

   c := pb.NewHelloClient(conn)

  

   // Contact the server and print out its response.

   name := defaultName

   if len(os.Args) > 1 {

      name = os.Args[1]

   }

   //5秒超时

   ctx, cancel := context.WithTimeout(context.Background(), time.Second*5)

   defer cancel()

   r, err := c.SayHello(ctx, &pb.HelloRequest{Name: name})

   if err != nil {

      log.Fatalf("could not greet: %v", err)

   }

   log.Printf("Hello: %s", r.Message)

}

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
回答: 错误提示中提到了一个未知的标志"--go-grpc",这可能是因为你的命令中使用了错误的标志。正确的命令应该是"protoc --go-grpc_out=. --go-grpc_opt=paths=source_relative user.proto"。请注意,标志"--go-grpc_out"和"--go-grpc_opt"之间应该有一个下划线"_",而不是一个空格。另外,你还需要确保你已经安装了正确的go协议编译器插件。你可以使用以下命令重新安装插件:"$ go install google.golang.org/protobuf/cmd/protoc-gen-go@latest"和"$ go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest"。\[1\]\[2\]\[3\] #### 引用[.reference_title] - *1* *2* [使用protoc编译grpc问题记录(--go_out: protoc-gen-go: plugins are not supported;)](https://blog.csdn.net/m0_57777971/article/details/127864341)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insert_down1,239^v3^insert_chatgpt"}} ] [.reference_item] - *3* [protoc-gen-go: plugin are not supported;use ‘protoc --go-grpc_out=...‘ to generate gRPC 的问题](https://blog.csdn.net/weixin_42875684/article/details/125652895)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insert_down1,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值