gRPC的使用(Go客户端)

下载protobuf编译器(Go版)
[root@localhost src]# go install google.golang.org/protobuf/cmd/protoc-gen-go@latest
[root@localhost src]# go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest
[root@localhost src]# ls /root/go/bin/
protoc-gen-go  protoc-gen-go-grpc
[root@localhost src]#
 
 
 
把/root/go/bin目录加入系统环境变量
[root@localhost ~]# vim /etc/profile
export PATH=$PATH:/program/nginx/sbin
export PATH=$PATH:/program/mysql/bin
export PATH=$PATH:/program/php/bin
export PATH=$PATH:/program/protoc/bin
export PATH=$PATH:$(go env GOPATH)/bin
[root@localhost ~]# source /etc/profile
[root@localhost ~]# protoc-gen-go --version
protoc-gen-go v1.30.0
[root@localhost ~]# protoc-gen-go-grpc --version
protoc-gen-go-grpc 1.3.0
[root@localhost ~]#



proto/calculator.proto文件

syntax = "proto3"; // 使用proto3语法

package proto; // 包名,如无特殊需求一般和*.proto文件所在目录同名

option go_package = "./"; // protoc生成的*.go文件的保存目录,这里设置为当前目录

// 定义服务(和面向对象里的接口很类似,只定义方法名、形参、返回值,具体功能由服务端去实现)
service Calculator {
  rpc Add(Nums)      returns (Result) {} // 加法运算
  rpc Subtract(Nums) returns (Result) {} // 减法运算
  rpc Multiply(Nums) returns (Result) {} // 乘法运算
  rpc Divide(Nums)   returns (Result) {} // 除法运算
}

// 形参
message Nums  {
  double num1 = 1; // 操作数1
  double num2 = 2; // 操作数2
}

// 返回值
message Result  {
  double num = 1; // 运算结果
  string error = 2; // 错误信息
}

// ========== 说明 ========== //
// 1、进入当前*.proto文件所在目录的上一级目录,执行如下命令生成*.go文件:
//    protoc --go_out=. --go_opt=paths=source_relative --go-grpc_out=. --go-grpc_opt=paths=source_relative proto/calculator.proto
//    执行完上面的命令后会在当前目录生成calculator.pb.go和calculator_grpc.pb.go两个文件,这两个文件不需要进行任何修改,直接使用即可。
// 2、如果使用PHP实现客户端可执行如下命令生成*.php文件:
//    protoc --proto_path=. --php_out=. --grpc_out=. --plugin=protoc-gen-grpc=/usr/local/bin/grpc_php_plugin proto/calculator.proto



服务端代码

package main

import (
   "context"
   "fmt"
   proto "go-src/grpc/proto"
   "google.golang.org/grpc"
   "net"
)

type Calculator struct {
   proto.UnimplementedCalculatorServer // 重要提醒:必须继承以“Unimplemented”开头的结构体。
}

// Add 加法运算
func (calculator *Calculator) Add(_ context.Context, nums *proto.Nums) (result *proto.Result, err error) {
   fmt.Println("有客户端调用Calculator.Add()")

   result = new(proto.Result)
   err = nil

   (*result).Num = (*nums).Num1 + (*nums).Num2
   return
}

// Subtract 减法运算
func (calculator *Calculator) Subtract(_ context.Context, nums *proto.Nums) (result *proto.Result, err error) {
   fmt.Println("有客户端调用Calculator.Subtract()")

   result = new(proto.Result)
   err = nil

   (*result).Num = (*nums).Num1 - (*nums).Num2
   return
}

// Multiply 乘法运算
func (calculator *Calculator) Multiply(_ context.Context, nums *proto.Nums) (result *proto.Result, err error) {
   fmt.Println("有客户端调用Calculator.Multiply()")

   result = new(proto.Result)
   err = nil

   (*result).Num = (*nums).Num1 * (*nums).Num2
   return
}

// Divide 除法运算
func (calculator *Calculator) Divide(_ context.Context, nums *proto.Nums) (result *proto.Result, err error) {
   fmt.Println("有客户端调用Calculator.Divide()")

   result = new(proto.Result)
   err = nil

   if (*nums).Num2 == 0 {
      (*result).Error = "除数不能为零"
   } else {
      (*result).Num = (*nums).Num1 / (*nums).Num2
   }

   return
}

func main() {
   var listener net.Listener
   var err error

   listener, err = net.Listen("tcp", ":10086")
   if err != nil {
      panic("设置gRPC服务端口失败:" + err.Error())
   }

   defer func(listener net.Listener) {
      _ = listener.Close()
   }(listener)

   // 创建gRPC服务器实例
   var grpcServer = grpc.NewServer()

   // 注册服务
   proto.RegisterCalculatorServer(grpcServer, new(Calculator))

   // 启动服务器
   err = (*grpcServer).Serve(listener)
   if err != nil {
      panic("启动gRPC服务器失败:" + err.Error())
   }
}



客户端代码

package main

import (
   "context"
   "fmt"
   proto "go-src/grpc/proto"
   "google.golang.org/grpc"
   "google.golang.org/grpc/credentials/insecure"
)

func main() {
   conn, err := grpc.Dial(":10086", grpc.WithTransportCredentials(insecure.NewCredentials()))
   if err != nil {
      panic("连接RPC服务器失败:" + err.Error())
   }

   defer func(conn *grpc.ClientConn) {
      _ = conn.Close()
   }(conn)

   client := proto.NewCalculatorClient(conn)

   nums := new(proto.Nums)
   result := new(proto.Result)

   // ========== 加法运算 ========== //
   (*nums).Num1 = 5
   (*nums).Num2 = 2
   result, err = client.Add(context.Background(), nums)
   if err != nil {
      fmt.Println("调用Calculator.Add()失败:" + err.Error())
   } else {
      fmt.Printf("调用Calculator.Add()成功:%v + %v = %v \n", (*nums).Num1, (*nums).Num2, (*result).Num)
   }

   // ========== 减法运算 ========== //
   (*nums).Num1 = 5
   (*nums).Num2 = 2
   result, err = client.Subtract(context.Background(), nums)
   if err != nil {
      fmt.Println("调用Calculator.Subtract()失败:" + err.Error())
   } else {
      fmt.Printf("调用Calculator.Subtract()成功:%v - %v = %v \n", (*nums).Num1, (*nums).Num2, (*result).Num)
   }

   // ========== 乘法运算 ========== //
   (*nums).Num1 = 5
   (*nums).Num2 = 2
   result, err = client.Multiply(context.Background(), nums)
   if err != nil {
      fmt.Println("调用Calculator.Multiply()失败:" + err.Error())
   } else {
      fmt.Printf("调用Calculator.Multiply()成功:%v * %v = %v \n", (*nums).Num1, (*nums).Num2, (*result).Num)
   }

   // ========== 除法运算(除数不为零) ========== //
   (*nums).Num1 = 5
   (*nums).Num2 = 2
   result, err = client.Divide(context.Background(), nums)
   if err != nil {
      fmt.Println("调用Calculator.Divide()失败:" + err.Error())
   } else {
      if (*result).Error != "" {
         fmt.Println("调用Calculator.Divide()出错:" + (*result).Error)
      } else {
         fmt.Printf("调用Calculator.Divide()成功:%v / %v = %v \n", (*nums).Num1, (*nums).Num2, (*result).Num)
      }
   }

   // ========== 除法运算(除数为零) ========== //
   (*nums).Num1 = 5
   (*nums).Num2 = 0
   result, err = client.Divide(context.Background(), nums)
   if err != nil {
      fmt.Println("调用Calculator.Divide()失败:" + err.Error())
   } else {
      if (*result).Error != "" {
         fmt.Println("调用Calculator.Divide()出错:" + (*result).Error)
      } else {
         fmt.Printf("调用Calculator.Divide()成功:%v / %v = %v \n", (*nums).Num1, (*nums).Num2, (*result).Num)
      }
   }
}

// ========== 输出结果·开始 ========== //
// 用Calculator.Add()成功:5 + 2 = 7
// 调用Calculator.Subtract()成功:5 - 2 = 3
// 调用Calculator.Multiply()成功:5 * 2 = 10
// 调用Calculator.Divide()成功:5 / 2 = 2.5
// 调用Calculator.Divide()出错:除数不能为零
// ========== 输出结果·结束 ========== //

Copyright © 2024 码农人生. All Rights Reserved