24 GRPC微服务
IDL(Interface description Language)文件:通过一种中立的方式来描述接口,使得在不同平台上的不同的对象和不同语言编写的程序可以互相通信。
下面使用proto作为IDL文件。
1.proto文件规则
syntax="proto3";
package idl;
option go_package = "./idl/my_proto;student_service";
import "google/protobuf/timestamp.proto"; message Student { string name = 1; repeated string Location = 4; map<string,float> Scores = 3; bool Gender = 5; int32 Age = 6; float Height = 7; google.protobuf.Timestamp Birthday = 8; }
message Request { string studentId = 1; }
service StudentService { rpc GetStudentInfo (Request) returns (Student); }
|
通过以下命令(之一)把proto文件转为go文件:
protoc --go_out=plugins=grpc:. --proto_path=./idl -I=./idl/third_proto student_service.proto #go_out protoc --gogofaster_out=plugins=grpc:. --proto_path=./idl -I=./idl/third_proto student_service.proto #gogofaster_out
|
-
go_out
可以换成中的go可以换成gogofaster等其它指令
-
grpc:.
中的.
表示基准地址,与文件中的go_package
路径共同生成go文件的最终地址。
-
proto_path
用于指定原始的输入文件在哪个目录下
-
-I
用于指定引用的proto
文件所在路径,再从文件中的import
路径来共同引用到那个proto
文件。
2.实现proto生成的接口并注册服务
在proto文件中定义了GetStudentInfo接口,你需要在自己的go文件中实现它。
package main
import ( "context" "errors" "fmt" "github.com/redis/go-redis/v9" "google.golang.org/grpc" student_service "grpc/idl/my_proto" "net" "strconv" )
func GetStudentInfo(studentId string) student_service.Student { client := redis.NewClient(&redis.Options{ Addr: "172.16.136.8:6379", Password: "123456", DB: 0, }) ctx := context.TODO() stu := student_service.Student{} for field, value := range client.HGetAll(ctx, studentId).Val() { if field == "Name" { stu.Name = value } else if field == "Age" { age, err := strconv.Atoi(value) if err != nil { stu.Age = int32(age) } } else if field == "Height" { height, err := strconv.ParseFloat(value, 10) if err != nil { stu.Height = float32(height) } } } return stu }
type StudentServer struct { }
func (s *StudentServer) GetStudentInfo(ctx context.Context, request *student_service.Request) (*student_service.Student, error) { defer func() { if err := recover(); err != nil { fmt.Printf("接口出错:%v\n", err) } }() studentId := request.StudentId if len(studentId) == 0 { return nil, errors.New("student id is empty") } student := GetStudentInfo(studentId) return &student, nil }
func main() { list, err := net.Listen("tcp", ":2346") if err != nil { panic(err) } server := grpc.NewServer() student_service.RegisterStudentServiceServer(server, new(StudentServer)) err = server.Serve(list) if err != nil { panic(err) }
}
|
3.客户端测试rpc
使用grpc的Dial去连接服务器。
package main
import ( "context" "fmt" "google.golang.org/grpc" student_service "grpc/idl/my_proto" "testing" )
func TestService(t *testing.T) { conn, err := grpc.Dial("127.0.0.1", grpc.WithInsecure()) if err != nil { fmt.Printf("连接grpc服务器失败:%+v", err) t.Fail() } defer conn.Close() client := student_service.NewStudentServiceClient(conn) resp, err := client.GetStudentInfo(context.TODO(), &student_service.Request{StudentId: "学生1"}) if err != nil { fmt.Printf("调用grpc服务器失败:%+v", err) t.Fail() } fmt.Printf("Name %s Age %d Height %.1f\n", resp.Name, resp.Age, resp.Height) }
|