zoukankan      html  css  js  c++  java
  • grpc

    一、什么是 Protobuf

    Protobuf是Protocol Buffers的简称,Google公司开发的一种数据描述语言,用于描述一种轻便高效的结构化数据存储格式
    跨语言、可扩展的序列化结构数据格式
    开发者可以通过Protobuf附带的工具生成代码并实现将结构化数据序列化的功能。

    Protobuf中最基本的数据单元是message,类似于Go中的结构体,在message中可以嵌套message或其它的基础数据类型的成员。

    .proto文件定义

    syntax = "proto3";  //指定使用proto3语法
    
    message SearchRequest {
      //保留字段
      reserved 2, 15, 9 to 11;
      reserved "foo", "bar";
    
      //字段出现次数--字段类型--字段名--唯一字段编号(不可重复)
      string query = 1;
      int32 page_number = 2;
      int32 result_per_page = 3;
      repeated string snippets = 4;  
    
      //枚举
      enum Corpus {
        UNIVERSAL = 0;
        WEB = 1;
        IMAGES = 2;
        LOCAL = 3;
        NEWS = 4;
        PRODUCTS = 5;
        VIDEO = 6;
      }
      Corpus corpus = 4;
     
      //message嵌套
      message Result {
        string url = 1;
        string title = 2;
        repeated string snippets = 3;
     }
     Result results = 10;
    }
    
    • singular 可以有0或者1个
    • repeated 可以有任意多个该字段值
    • 保留字段,指定保留的字段编号和字段名称。如果未来有人用了这些字段标识那么在编译时protocol buffer的编译器会报错。
      意思是,这些字段和编号不可以用了,常用于当你删掉或者注释掉message中的一个字段时,未来其他开发者在更新message定义时避免再重用之前的字段编号。防止他们意外载入了老版本的数据

    定义服务,类似于定义一个接口,声明其包含的方法

    service SearchService {
      rpc Search (SearchRequest) returns (SearchResponse);
    }
    

    生成代码

    下载protoc编译器
    protoc --proto_path=IMPORT_PATH --go_out=DST_DIR
    指定输入和输出目录路径,--language_out 指定对应语言版本, 生成对应版本代码文件,如go语言版本的 .pd.go 文件

    二、代码案列

    1、创建proto文件(spider.proto)

    syntax = "proto3";  // 协议为proto3
    
    package spider;  // 包名
    
    // 发送请求
    message SendAddress {
        // 发送的参数字段
        // 参数类型 参数名 标识号(不可重复)
        string address = 1;  // 要请求的地址
        string method = 2;  // 请求方式
    }
    
    // 返回响应
    message GetResponse {
        // 接收的参数字段
        // 参数类型 参数名 标识号
        int32 httpCode = 1;  // http状态码
        string response = 2;  // 返回体
    }
    
    // 定义服务,可定义多个服务,每个服务可多个接口
    service GoSpider {
        // rpc请求 请求的函数 (发送请求参数) returns (返回响应的参数)
        rpc GetAddressResponse (SendAddress) returns (GetResponse);
    }
    

    2、编译生成 spider.pb.go 代码文件

    3、编写服务端

    package main
    
    import (
    	"context"
    	"google.golang.org/grpc"
    	"google.golang.org/grpc/reflection"
    	"io/ioutil"
    	"net"
    	"net/http"
    	"server/spider"  //编译后的 spider.pb.go 代码文件
    )
    
    type server struct{}  //声明一个结构体,并实现服务接口中方法
    
    const (
    	// Address 监听地址
    	Address string = "localhost:8080"
    	// Method 通信方法
    	Method string = "tcp"
    )
    
    // 接收client端的请求,函数名需保持一致
    // ctx参数必传
    func (s *server) GetAddressResponse(ctx context.Context, a *spider.SendAddress) (*spider.GetResponse, error) {
    	// 逻辑写在这里
    	switch a.Method {
    	case "get", "Get", "GET":
    		// 演示微服务用,故只写get示例
    		status, body, err := get(a.Address)
    		if err != nil {
    			return nil, err
    		}
    		res := spider.GetResponse{
    			HttpCode: int32(status),
    			Response: body,
    		}
    		return &res, nil
    	}
    	return nil, nil
    }
    
    func get(address string) (s int, r string, err error) {
    	// get请求
    	resp, err := http.Get(address)
    	if err != nil {
    		return
    	}
    	defer resp.Body.Close()
    	s = resp.StatusCode
    	body, err := ioutil.ReadAll(resp.Body)
    	if err != nil {
    		return
    	}
    	r = string(body)
    	return
    }
    
    func main() {
    	// 监听本地端口
    	listener, err := net.Listen(Method, Address)
    	if err != nil {
    		return
    	}
    	s := grpc.NewServer()                       // 创建GRPC
    	spider.RegisterGoSpiderServer(s, &server{}) // 在GRPC服务端注册服务
    	reflection.Register(s) // 在GRPC服务器注册服务器反射服务,这个和CLI有关(便于开发时界面调试) 本身和服务无关
    
    	// Serve方法接收监听的端口,每到一个连接创建一个ServerTransport,和server的goroutine
    	// 这个goroutine读取GRPC请求,调用已注册的处理程序进行响应
    	err = s.Serve(listener)
    	if err != nil {
    		return
    	}
    }
    

    4、编写客户端

    package main
    
    import (
    	"client/spider"
    	"context"
    	"google.golang.org/grpc"
    )
    
    import "fmt"
    
    const (
    	// Address server端地址
    	Address string = "localhost:8080"
    )
    
    func main() {
    	// 连接服务器
    	conn, err := grpc.Dial(Address, grpc.WithInsecure())
    	if err != nil {
    		fmt.Println(err)
    		return
    	}
    	defer conn.Close()
    
    	// 连接GRPC
    	c := spider.NewGoSpiderClient(conn)
    	// 创建要发送的结构体
    	req := spider.SendAddress{
    		Address: "http://www.baidu.com",
    		Method:  "get",
    	}
    	// 调用server的注册方法
    	r, err := c.GetAddressResponse(context.Background(), &req)
    	if err != nil {
    		fmt.Println(err)
    		return
    	}
    	// 打印返回值
    	fmt.Println(r)
    }
    
  • 相关阅读:
    在WinForm中通过C#调用CHM帮助文件
    筹备婚礼之音乐
    挖掘Microsoft Visual Studio 里面的资源之数据库连接配置
    好的Sql语句也能提高效率
    任务安排
    (读书笔记)
    MicroTeam 博客书写注意事项
    泛海精灵的用户分析:补充【Song Xie】
    什么是测试
    [scrum]2010.12.23
  • 原文地址:https://www.cnblogs.com/fanzou/p/13542490.html
Copyright © 2011-2022 走看看