• golang——gRPC学习


    1、获取gRPC

    环境变量GOPATH的src目录下执行:

    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文件

    gRPC 允许定义4种类型的 service 方法

    (1)编写test.proto

    syntax = "proto3";
    package test;
    
    //参数
    message Question{
        string question_str = 1;
    }
    
    //返回
    message Answer{
        string answer_str = 1;
    }
    
    //定义服务
    service Test{
        //简单RPC
        rpc GetAnswer1(Question) returns (Answer){}
        //服务端流式RPC
        rpc GetAnswer2(Question) returns (stream Answer){}
        //客户端流式RPC
        rpc GetAnswer3(stream Question) returns (Answer){}
        //双向流式RPC
        rpc GetAnswer4(stream Question) returns (stream Answer){}
    }
    

    (2)生成文件test.pb.go

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

    3、服务端

    package main
    
    import (
    	"context"
    	"fmt"
    	"io"
    	"log"
    	"net"
    	"test/grpc/test"
    
    	"google.golang.org/grpc"
    )
    
    type testServer struct{}
    
    //简单RPC
    //客户端一次请求,服务端一次响应
    func (*testServer) GetAnswer1(ctx context.Context, q *test.Question) (*test.Answer, error) {
    	answer := test.Answer{AnswerStr: fmt.Sprintf("Question:%s;Answer:%s。", q.QuestionStr, "Answer1")}
    	return &answer, nil
    }
    
    //服务端流式RPC
    //客户端一次请求,服务端多次响应
    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。
    ", 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、客户端

    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、输出

    // 简单RPC===========================
    // Question:问题11111111?;Answer:Answer1。
    // 服务端流式RPC===========================
    // Question:问题11111111?;Answer:Answer1。
    // Question:问题11111111?;Answer:Answer2。
    // Question:问题11111111?;Answer:Answer3。
    // 客户端流式RPC===========================
    // Question:问题1;Answer:Answer1。
    // Question:问题2;Answer:Answer2。
    // Question:问题3;Answer:Answer3。
    
    // 双向流式RPC===============================
    // Question:问题1;Answer:Answer1。
    // Question:问题2;Answer:Answer2。
    // Question:问题3;Answer:Answer3。
    // Question:问题4;Answer:Answer4。
    
    笃志:“博学而笃志,切问而近思,仁在其中矣。”
    弘毅:“士不可以不弘毅,任重而道远。”
    止于至善:“大学之道,在明明德,在亲民,在止于至善。”
    关注:笃志弘毅,止于至善
  • 相关阅读:
    Flutter实战视频-移动电商-11.首页_屏幕适配方案讲解
    Flutter实战视频-移动电商-10.首页_FlutterSwiper轮播效果制作
    Flutter实战视频-移动电商-09.首页_项目结构建立和获取数据
    Flutter实战视频-移动电商-08.Dio基础_伪造请求头获取数据
    【RQNOJ】460 诺诺的队列
    NYOJ 483 Nightmare 【广搜】+【无标记】
    冒泡,简单选择,直接插入排序(Java版)
    基于MFC与第三方类CWebPage的百度地图API开发范例
    USACO 1.2 Palindromic Squares (进制转换,回文)
    与《新走遍美国》的邂逅
  • 原文地址:https://www.cnblogs.com/dzhy/p/11103429.html
Copyright © 2020-2023  润新知