1, get gRPC
Execution environment variable GOPATH src directory:
git clone https://github.com/grpc/grpc-go.git google.golang.org/grpc
git clone https://github.com/golang/net.git golang.org/x/net
git clone https://github.com/golang/text.git golang.org/x/text
go get -u github.com/golang/protobuf/protoc-gen-go
git clone https://github.com/google/go-genproto.git google.golang.org/genproto
go install google.golang.org/grpc
2, proto file
gRPC allows to define four types of service method .
(1) write test.proto
= syntax "proto3"; Package Test; // Parameter Message {Question String = question_str. 1; } // Returns Message {Answer The String = answer_str. 1; } // define service -Service the Test { // simply the RPC RPC GetAnswer1 (Question) Returns (Answer The) {} // server streaming the RPC RPC GetAnswer2 (Question) Returns (Answer The stream) {} // streaming client the RPC RPC GetAnswer3 (Question stream) Returns (Answer The) {} // bidirectional streaming the RPC RPC GetAnswer4 (Question Stream) Returns (Answer The Stream) {} }
(2) generating a document test.pb.go
protoc --go_out=plugins=grpc:. test.proto
3, the server
main Package Import ( "context" "FMT" "IO" "log" "NET" "Test / GRPC / Test" "google.golang.org/grpc" ) type testServer struct {} // simply the RPC // a client request, the server response time FUNC (* testServer) GetAnswer1 (CTX context.Context, Q * test.Question) (test.Answer *, error) { answer: = {AnswerStr test.Answer: fmt.Sprintf ( "Question:% S; answer The:.% S ", q.QuestionStr," answer1 ")} return & answer, nil } // server streaming the RPC // a client request, the server response times func (* testServer) GetAnswer2 (q test.Question *, Stream test.Test_GetAnswer2Server) {error for I: =. 1; I <=. 3; I ++ { answer := test.Answer{AnswerStr: fmt.Sprintf("Question:%s;Answer:%s%d。", q.QuestionStr, "Answer", i)} if err := stream.Send(&answer); err != nil { return err } } return nil } //客户端流式RPC //客户端多次请求,服务端一次响应 func (*testServer) GetAnswer3(stream test.Test_GetAnswer3Server) error { answer := test.Answer{} for i := 1; ; i++ { question, err := stream.Recv() if err == io.EOF { return stream.SendAndClose(&answer) } if err != nil { return err } answer.AnswerStr = fmt.Sprintf("%sQuestion:%s;Answer:Answer%d。\n", answer.AnswerStr, question.QuestionStr, i) } } //双向流式RPC //客户端多次请求,服务端多次响应 func (*testServer) GetAnswer4(stream test.Test_GetAnswer4Server) error { for i := 1; ; i++ { question, err := stream.Recv() if err == io.EOF { return nil } if err != nil { return err } answer := test.Answer{AnswerStr: fmt.Sprintf("Question:%s;Answer:%s%d。", question.QuestionStr, "Answer", i)} if err = stream.Send(&answer); err != nil { return err } } } func main() { lis, err := net.Listen("tcp", "127.0.0.1:5000") if err != nil { log.Fatalf("failed to listen: %v", err) } grpcServer := grpc.NewServer() test.RegisterTestServer(grpcServer, &testServer{}) grpcServer.Serve(lis) }
4, the client
package main import ( "context" "fmt" "io" "log" "test/grpc/test" "google.golang.org/grpc" ) func main() { conn, err := grpc.Dial("127.0.0.1:5000", grpc.WithInsecure()) if err != nil { log.Fatalf("fail to dial: %v", err) } defer conn.Close() client := test.NewTestClient(conn) fmt.Println("简单RPC===========================") question := test.Question{QuestionStr: "问题11111111?"} answer, err := client.GetAnswer1(context.Background(), &question) if err != nil { log.Fatalf("fail to GetAnswer1: %v", err) } fmt.Println(answer.AnswerStr) fmt.Println("服务端流式RPC===========================") stream, err := client.GetAnswer2(context.Background(), &question) if err != nil { log.Fatalf("fail to GetAnswer2: %v", err) } for { answer, err := stream.Recv() if err == io.EOF { break } if err != nil { log.Fatalf("%v.GetAnswer2, %v", client, err) } fmt.Println(answer.AnswerStr) } fmt.Println("客户端流式RPC===========================") stream3, err := client.GetAnswer3(context.Background()) if err != nil { log.Fatalf("fail to GetAnswer3: %v", err) } for i := 1; i <= 3; i++ { question := test.Question{QuestionStr: fmt.Sprintf("问题%d", i)} if err = stream3.Send(&question); err != nil { log.Fatalf("fail to GetAnswer3 Send: %v", err) } } answer, err = stream3.CloseAndRecv() if err != nil { log.Fatalf("fail to GetAnswer3 CloseAndRecv: %v", err) } fmt.Println(answer.AnswerStr) fmt.Println("双向流式RPC===============================") done := make(chan bool) stream4, err := client.GetAnswer4(context.Background()) if err != nil { log.Fatalf("fail to GetAnswer4: %v", err) } //接受服务端响应 go func() { for { answer, err := stream4.Recv() if err == io.EOF { close(done) return } if err != nil { log.Fatalf("%v.GetAnswer4, %v", client, err) } fmt.Println(answer.AnswerStr) } }() //客户端发送请求 for i := 1; i <= 4; i++ { question := test.Question{QuestionStr: fmt.Sprintf("问题%d", i)} if err = stream4.Send(&question); err != nil { log.Fatalf("fail to GetAnswer3 Send: %v", err) } } stream4.CloseSend() <-done }
5, output
// =========================== simple RPC // Question: 11111111 problem? ; Answer: Answer1. // server streaming =========================== RPC // Question: 11111111 problem? ; Answer: Answer1. // Question: 11111111 problem? ; Answer: Answer2. // Question: 11111111 problem? ; Answer: Answer3. // client streaming =========================== RPC // Question: question 1; Answer: Answer1. // Question: question 2; Answer: Answer2. // Question: issue 3; Answer: Answer3. // bi-directional flow =============================== RPC // Question: question 1; Answer: Answer1. // Question: question 2; Answer: Answer2. // Question: issue 3; Answer: Answer3. // Question: question 4; Answer: Answer4.