zoukankan      html  css  js  c++  java
  • go-grpc 基本使用

    gRPC是什么?

    gRPC是什么可以用官网的一句话来概括

    A high-performance, open-source universal RPC framework

    所谓RPC(remote procedure call 远程过程调用)框架实际是提供了一套机制,使得应用程序之间可以进行通信,而且也遵从server/client模型。使用的时候客户端调用server端提供的接口就像是调用本地的函数一样。如下图所示就是一个典型的RPC结构图。

    RPC通信

    gRPC有什么好处以及在什么场景下需要用gRPC
    既然是server/client模型,那么我们直接用restful api不是也可以满足吗,为什么还需要RPC呢?下面我们就来看看RPC到底有哪些优势

    gRPC vs. Restful API

    gRPC和restful API都提供了一套通信机制,用于server/client模型通信,而且它们都使用http作为底层的传输协议(严格地说, gRPC使用的http2.0,而restful api则不一定)。不过gRPC还是有些特有的优势,如下:

    gRPC可以通过protobuf来定义接口,从而可以有更加严格的接口约束条件。

    另外,通过protobuf可以将数据序列化为二进制编码,这会大幅减少需要传输的数据量,从而大幅提高性能。
    gRPC可以方便地支持流式通信(理论上通过http2.0就可以使用streaming模式, 但是通常web服务的restful api似乎很少这么用,通常的流式数据应用如视频流,一般都会使用专门的协议如HLS,RTMP等,这些就不是我们通常web服务了,而是有专门的服务器应用。)

    Protobuf是什么

    官方文档: https://developers.google.com/protocol-buffers

    Protobuf实际是一套类似Json或者XML的数据传输格式和规范,用于不同应用或进程之间进行通信时使用。通信时所传递的信息是通过Protobuf定义的message数据结构进行打包,然后编译成二进制的码流再进行传输或者存储。

    Protobuf的优点

    相比较而言,Protobuf有如下优点:

    • 足够简单
    • 序列化后体积很小:消息大小只需要XML的1/10 ~ 1/3
    • 解析速度快:解析速度比XML快20 ~ 100倍
    • 多语言支持
    • 更好的兼容性,Protobuf设计的一个原则就是要能够很好的支持向下或向上兼容

    安装Protobuf

    1. 官网下载二进制文件
      https://github.com/protocolbuffers/protobuf/releases

    根据自己的系统版本下载指定的稳定版本文件

    我这边是 MAC 就下载 protoc-3.11.4-osx-x86_64.zip文件

    1. 添加可执行文件到环境变量

    2. 为了基础protobuf文件,使用protoc工具编译出go相关文件,需要安装一个插件

    $ go get github.com/golang/protobuf/protoc-gen-go
    

    GRPC示例

    安装grpc

    $ go get -u google.golang.org/grpc
    

    GRPC服务端

    目录结构

    .
    ├── main.go // 入口文件
    ├── pbfile  // protobuf 中间文件
    │   └── Prob.proto
    ├── pbservices  // 根据中间文件生成的go文件
    │   └── Prob.pb.go
    └── services    // 根据生成的go文件的实现
        └── Prob.go
    

    protobuf 中间文件

    // proto 文件版本
    syntax = "proto3";
    // 生成文件的包名
    package services;
    
    // 请求结构体
    message ProbRequest {
        int32 Pid = 1;
    }
    
    // 响应结构体
    message ProbResponse {
        float Price = 1;
    }
    
    // 定义rpc接口
    service ProbService {
        rpc GetProductPrice (ProbRequest) returns (ProbResponse)
    }
    

    使用中间文件生成go文件

    $ cd pbfile/
    $ protoc --go_out=plugins=grpc:../pbservices Prob.proto
    

    实现生成的go文件的接口

    // services/Prob.go
    package services
    
    import (
    	"context"
    	"pbservices"
    )
    
    type ProbService struct {
    }
    
    func (this *ProbService) GetProductPrice(context.Context, request *pbservices.ProbRequest) (*pbservices.ProbResponse, error) {
    	return &pbservices.ProbResponse{Price: 10}, nil
    }
    

    创建rpc服务文件

    package main
    
    import (
    	"pbservices"
    	"services"
    	"google.golang.org/grpc"
    	"log"
    	"net"
    )
    
    func main() {
    	// 服务端启用安全证书
    	//cred, err := credentials.NewServerTLSFromFile("./keys/server.crt", "./keys/server.key")
    	//if err != nil {
    	//	log.Fatal(err)
    	//}
    
    	// 创建服务
    	//rpcserver := grpc.NewServer(grpc.Creds(cred))
    	rpcserver := grpc.NewServer()
    
    	// 注册
    	pbservices.RegisterProbServicesServer(rpcserver, &services.ProbService{})
    
    	// 启动监听
    	lis, err := net.Listen("tcp", ":8081")
    	if err != nil {
    		log.Fatal(err)
    	}
    	err = rpcserver.Serve(lis)
    	if err != nil {
    		log.Fatal(err)
    	}
    }
    

    GRPC客户端

    目录结构

    .
    ├── main.go     // 入口文件
    └── pbservices  // 根据中间文件生成的go文件
        └── Prob.pb.go
    

    客户端实现

    package main
    
    import (
    	"context"
    	"fmt"
    	"pbservices"
    	"google.golang.org/grpc"
    	"log"
    )
    
    func main() {
    	// 启用安全证书
    	//cred, err := credentials.NewClientTLSFromFile("./keys/server.crt", "mazhichao.com")
    	//if err != nil {
    	//	log.Fatal(err)
    	//}
    
    	//conn, err := grpc.Dial(":8081", grpc.WithTransportCredentials(cred))
    	// grpc.WithInsecure() 忽略安全
    	conn, err := grpc.Dial(":8081", grpc.WithInsecure())
    	if err != nil {
    		log.Fatal(err)
    	}
    	defer conn.Close()
    
    	client := pbservices.NewProbServicesClient(conn)
    	req := &pbservices.ProbRequest{Pid: 1}
    	response, err := client.GetProductPrice(context.Background(), req)
    	if err != nil {
    		log.Fatal(err)
    	}
    	fmt.Println(response.Price)
    }
    
  • 相关阅读:
    common-fileupload上传图片并显示图片
    common-fileupload上传文件
    Hibernate映射文件配置(hbm.xml和注解方式)
    hdu1272:小希的迷宫(并查集)
    hdu1272:小希的迷宫(并查集)
    hdu1102:Constructing Roads(最小生成树)
    hdu1102:Constructing Roads(最小生成树)
    hdu1054:Strategic Game(最小点覆盖)
    hdu1054:Strategic Game(最小点覆盖)
    hdu2255:奔小康赚大钱(KM)
  • 原文地址:https://www.cnblogs.com/zhichaoma/p/12809557.html
Copyright © 2011-2022 走看看