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