Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

.proto 协议缓冲文件介绍 #55

Open
huangshuwei opened this issue May 8, 2021 · 0 comments
Open

.proto 协议缓冲文件介绍 #55

huangshuwei opened this issue May 8, 2021 · 0 comments
Labels

Comments

@huangshuwei
Copy link
Owner

huangshuwei commented May 8, 2021

前言

介绍 .proto 协议缓冲文件的基本用途,我们下面以一个helloworld 示例介绍。
示例项目:https://github.com/huangshuwei/vue-grpc-demo

什么是 .proto 协议缓冲文件

协议缓冲(Protocol Buffers),官方有很详细的协议缓冲的介绍。总结下有这些功能点:

  • Defining A Message Type
  • Scalar Value Types
  • Optional And Default Values
  • Enumerations
  • Using Other Message Types
  • Nested Types
  • Updating A Message Type
  • Extensions
  • Oneof
  • Maps
  • Packages
  • Defining Services
  • Options
  • Generating Your Classes

helloword 示例

我们只看客户端实现部分,假设已经定义好了一个 helloworld.proto 文件,内容如下:

syntax = "proto3";

package helloworld;

service Greeter {
  // unary call
  rpc SayHello(HelloRequest) returns (HelloReply);
  // server streaming call
  rpc SayRepeatHello(RepeatHelloRequest) returns (stream HelloReply);
}

message HelloRequest {
  string name = 1;
}

message RepeatHelloRequest {
  string name = 1;
  int32 count = 2;
}

message HelloReply {
  string message = 1;
}

生成Protobuf消息和客户端服务存根

根据 helloworld.proto文件我们可以生成Protobuf消息和客户端服务存根,如何生成可以参考windows环境生成Protobuf消息和客户端服务存根

操作成功后,会生成 helloworld_pb.js 和 helloworld_grpc_web_pb.js 文件。

helloworld_pb.js 文件会包含协议信息,而 helloworld_grpc_web_pb.js 文件则包含客户端操作的信息

helloworld.proto 文件分析-消息类型

通过关键字 message 定义了3个消息类型,分别是 HelloRequest、RepeatHelloRequest以及HelloReply

HelloRequest 消息,包含 string 类型的参数 name

message HelloRequest {
  string name = 1;
}

RepeatHelloRequest 消息,包含 string 类型的参数 nameint32 类型的参数 count

message RepeatHelloRequest {
  string name = 1;
  int32 count = 2;
}

HelloReply 消息,包含 string 类型的参数 message

message HelloReply {
  string message = 1;
}

helloworld.proto 文件分析-服务

通过关键字 service 定义服务(接口):

service Greeter {
  // unary call(一元模式)
  rpc SayHello(HelloRequest) returns (HelloReply);
  // server streaming call(服务端流模式)
  rpc SayRepeatHello(RepeatHelloRequest) returns (stream HelloReply);
}

可以看到,Greeter 对象包含两个服务。一元模式服务SayHello 和 服务端流模式SayRepeatHello服务。一元模式可以理解为客户端单次请求的方式,而服务端流模式可以理解为服务端推送方式。

客户端编写

获取消息类型对象,以及请求客户端对象

通过 helloworld_pb.js 文件获取消息类型对象。通过 helloworld_grpc_web_pb.js 文件获取客户端请求对象

// client.js
const {
  HelloRequest,
  HelloReply,
} = require("./service/proto/helloworld_pb.js");
const { GreeterClient } = require("./service/proto/helloworld_grpc_web_pb.js");

var client = new GreeterClient("http://" + window.location.hostname + ":8080", null, null);

SayHello 一元模式

此时我们可以通过 helloworld_pb.js 文件获取到这些协议信息。

给参数赋值,是通过消息类型的示例设置的。如HelloRequest 消息类型,它有一个 name 参数,name 赋值是通过 new HelloRequest().setName("参数值");

// client.js

// simple unary call
var request = new HelloRequest();
request.setName("World");

client.sayHello(request, {}, (err, response) => {
  if (err) {
    console.log(
      `Unexpected error for sayHello: code = ${err.code}` + `, message = "${err.message}"`
    );
  } else {
    console.log(response.getMessage());
  }
});

SayRepeatHello 服务端流模式

和一元模式不同的是,对于请求的接收,是通过流的模式。如下:

// client.js

// simple unary call
var request = new HelloRequest();
request.setName("World");

client.sayHello(request, {}, (err, response) => {
  if (err) {
    console.log(
      `Unexpected error for sayHello: code = ${err.code}` + `, message = "${err.message}"`
    );
  } else {
    console.log(response.getMessage());
  }
});

客户端请求完整代码:

// client.js
const {
  HelloRequest,
  RepeatHelloRequest,
  HelloReply,
} = require("./service/proto/helloworld_pb.js");
const { GreeterClient } = require("./service/proto/helloworld_grpc_web_pb.js");

var client = new GreeterClient("http://" + window.location.hostname + ":8080", null, null);

// simple unary call
var request = new HelloRequest();
request.setName("World");

client.sayHello(request, {}, (err, response) => {
  if (err) {
    console.log(
      `Unexpected error for sayHello: code = ${err.code}` + `, message = "${err.message}"`
    );
  } else {
    console.log(response.getMessage());
  }
});

// server streaming call
var streamRequest = new RepeatHelloRequest();
streamRequest.setName("World");
streamRequest.setCount(5);

var stream = client.sayRepeatHello(streamRequest, {});
stream.on("data", (response) => {
  console.log(response.getMessage());
});
stream.on("error", (err) => {
  console.log(`Unexpected stream error: code = ${err.code}` + `, message = "${err.message}"`);
});

总结

此时我们距离代码可以运行还有一段距离,下一篇将介绍 windows10 基于grpc-web 的 envoy 代理配置

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

1 participant