• grpc 快速入门


    gRPC 是一个现代的远程过程调用(RPC)框架,由 Google 开发。它使用 HTTP/2 作为传输协议,并采用 Protocol Buffers(protobuf)作为接口描述语言(IDL)。gRPC 提供高效的通信、语言无关性和跨平台支持,非常适合构建分布式系统。

    准备接口描述文件即 IDL

    	// /home/zhangshixing/protoc/temp/hello.proto
    	// 指定proto版本
    	syntax = "proto3";
    	// 指定包名
    	package mypackage;
    	// 指定文件生成的路径和包名
    	// ./hello为路径
    	// mytest为生成的包名
    	// 如果指定的go_package="./hello";则包名和路径同名(如果路径有多层,则包名和路径的最后一层相同)
    	//option go_package="./hello;mytest";
    	option go_package="./hello";
    	
    	// 定义Hello服务
    	service Hello {
    	  // 定义SayHello方法
    	  rpc SayHello(HelloRequest) returns (HelloReply) {}
    	}
    	
    	// HelloRequest 请求结构
    	message HelloRequest {
    	  string name = 1;
    	  string age = 2;
    	}
    	
    	// HelloReply 响应结构
    	message HelloReply {
    	  string message = 1;
    	}
    

    生成代码

    利用上文定义的接口文件,生成 golang 代码:

    protoc -I . --go_out=plugins=grpc:. hello.proto  生成 hello.pb.go 文件
    
    生成的代码主要是:结构体的编解码序列化代码 和 用于创建和发起 RPC 调用的桩代码
    

    服务端代码

    本质就是启动一个 rpcServer 监听指定端口,其中 pb.RegisterHelloServer(rpcServer, &helloSever) 的分析如下:

    1. RegisterHelloServer 是告诉 rpcServer 什么请求由谁处理;作用和普通 web server 的路由一样。
    2. HelloServer 的 sayHello 的具体逻辑是开发人员自定义实现的,不过其入参和返回值已经由IDL决定了
    package main
    
    import (
    	pb "awesomeProject/libadv/grpcdbg/hello"
    	"context"
    	"flag"
    	"fmt"
    	"google.golang.org/grpc"
    	"log"
    	"net"
    )
    
    type HelloServer struct {
    }
    
    func (*HelloServer) SayHello(ctx context.Context, request *pb.HelloRequest) (*pb.HelloReply, error) {
    	fmt.Printf("In the sayHello, param = %s, age = %s\n", request.GetName(), request.GetAge())
    	var helloReply pb.HelloReply
    	helloReply.Message = fmt.Sprintf("Hello %s", request.GetName())
    	return &helloReply, nil
    }
    
    var (
    	port = flag.Int("port", 50052, "The server port")
    )
    
    func main() {
    	/*
    	 * 修改 hello.proto 后,执行  protoc -I . --go_out=plugins=grpc:. hello.proto
    	 * from: https://blog.csdn.net/qq_30614345/article/details/131860694
    	 */
    	flag.Parse()
    	lis, err := net.Listen("tcp", fmt.Sprintf(":%d", *port))
    	if err != nil {
    		log.Fatalf("failed to listen: %v", err)
    	}
    
    	rpcServer := grpc.NewServer()
    	var helloSever HelloServer
    	pb.RegisterHelloServer(rpcServer, &helloSever)
    	log.Printf("server listening at %v", lis.Addr())
    	if err := rpcServer.Serve(lis); err != nil {
    		log.Fatalf("failed to serve: %v", err)
    	}
    }
    

    pb.RegisterHelloServer(rpcServer, &helloSever) 的源码:

    // 下面的代码来自第2步生产的 hello.pb.go
    func RegisterHelloServer(s *grpc.Server, srv HelloServer) {
    	s.RegisterService(&_Hello_serviceDesc, srv)  ---------告诉 rpcServer 什么请求由谁处理;作用和普通 web server 的路由一样
    }
    
    func _Hello_SayHello_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
        /* 第一个参数 srv 猜测会在 rpcServer 收到请求后,把 s.RegisterService(&_Hello_serviceDesc, srv)  的第二个参数传过来 */
        
    	in := new(HelloRequest)
    	if err := dec(in); err != nil {
    		return nil, err
    	}
    	if interceptor == nil {
    		return srv.(HelloServer).SayHello(ctx, in)
    	}
    	info := &grpc.UnaryServerInfo{
    		Server:     srv,
    		FullMethod: "/mypackage.Hello/SayHello",
    	}
    	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
    		return srv.(HelloServer).SayHello(ctx, req.(*HelloRequest))
    	}
    	return interceptor(ctx, in, info, handler)
    }
    
    var _Hello_serviceDesc = grpc.ServiceDesc{
    	ServiceName: "mypackage.Hello",
    	HandlerType: (*HelloServer)(nil),
    	Methods: []grpc.MethodDesc{
    		{
    			MethodName: "SayHello",
    			Handler:    _Hello_SayHello_Handler,
    		},
    	},
    	Streams:  []grpc.StreamDesc{},
    	Metadata: "hello.proto",
    }
    

    客户端代码

    package main
    
    import (
    	pb "awesomeProject/libadv/grpcdbg/hello"
    	"context"
    	"flag"
    	"google.golang.org/grpc/credentials/insecure"
    	"log"
    	"time"
    )
    import "google.golang.org/grpc"
    
    var defaultName = "world"
    var (
    	//addr = flag.String("addr", "localhost:50052", "the address to connect to")
    	addr = flag.String("addr", "127.0.0.1:50052", "the address to connect to")
    	name = flag.String("name", defaultName, "Name to greet")
    )
    
    
    func main() {
    	flag.Parse()
    
    	// Set up a connection to the server.
    	conn, err := grpc.Dial(*addr, grpc.WithTransportCredentials(insecure.NewCredentials()))
    	if err != nil {
    		log.Fatalf("did not connect: %v", err)
    	}
    	defer conn.Close()
    
    	helloClient := pb.NewHelloClient(conn)
    	// Contact the server and print out its response.
    	ctx, cancel := context.WithTimeout(context.Background(), time.Second)
    	defer cancel()
    
    	request := pb.HelloRequest{Name: *name, Age: "22"}
    	r, err := helloClient.SayHello(ctx, &request)
    	if err != nil {
    		log.Fatalf("could not greet: %v", err)
    	}
    	log.Printf("Greeting: %s", r.GetMessage())
    }
    
  • 相关阅读:
    基于MIMO+16QAM系统的VBLAST译码算法matlab仿真
    热门Java开发工具IDEA入门指南——离线环境下的注意事项
    操作系统之线程和进程
    【优化选址】遗传算法求解物流配送中心选址【含Matlab源码 1917期】
    HFS局域网分享文件的神器(附下载链接)
    【SpringBoot从入门到精通】00-SpringBoot 简介
    电路的设计方法
    图像识别(五)| 春天花开却不识?打开百度识图,残差和卷积带你识遍路边野花
    Postgresql的一个bug_涉及归档和pg_wal
    社区版MyApps低代码平台,免费即刻拥有!
  • 原文地址:https://blog.csdn.net/cpxsxn/article/details/143393349