» gRPC快速入门:Node.js » 3. 创建 proto 文件 » 3.1 定义服务

定义服务

第一步是使用 protocol buffers 定义一个 gRPC 服务和其方法的请求、响应类型。

完整 .proto 文件内容在 examples/protos/route_guide.proto

// Copyright 2015 gRPC authors.

syntax = "proto3";

option java_multiple_files = true;
option java_package = "io.grpc.examples.routeguide";
option java_outer_classname = "RouteGuideProto";
option objc_class_prefix = "RTG";

package routeguide;

service RouteGuide {
  rpc GetFeature(Point) returns (Feature) {}
  rpc ListFeatures(Rectangle) returns (stream Feature) {}
  rpc RecordRoute(stream Point) returns (RouteSummary) {}
  rpc RouteChat(stream RouteNote) returns (stream RouteNote) {}
}

// Point 由纬度经度对表示。
message Point {
  int32 latitude = 1;
  int32 longitude = 2;
}

// 一个纬度经度矩形,由对角线上的两个点 "lo" 和 "hi" 表示。
message Rectangle {
  // 矩形的一个角。
  Point lo = 1;

  // 矩形的另一个角。
  Point hi = 2;
}

// 要素指定了给定点的名称。
// 如果无法为要素命名,则名称为空。
message Feature {
  // 要素的名称。
  string name = 1;

  // 要素被检测到的位置。
  Point location = 2;
}

// RouteNote 是在给定点发送的消息。
message RouteNote {
  // 消息发送的位置。
  Point location = 1;

  // 要发送的消息。
  string message = 2;
}

// RouteSummary 是对 RecordRoute RPC 的响应消息。
//
// 它包含接收到的点数、经过的要素数以及每个点之间距离累加得出的总距离。
message RouteSummary {
  // 接收到的点数。
  int32 point_count = 1;

  // 遍历路线时通过的已知要素数。
  int32 feature_count = 2;

  // 覆盖的距离(单位:米)。
  int32 distance = 3;

  // 遍历所花费的时间(单位:秒)。
  int32 elapsed_time = 4;
}

要定义一个服务,在你的 .proto 文件中指定一个命名的 service

service RouteGuide {
   ...
}

然后在服务定义内部定义 rpc 方法,指定它们的请求和响应类型。gRPC 允许你定义四种类型的服务方法,这些方法在 RouteGuide 服务中都有使用:

  • 简单 RPC,(或者叫一元 RPC):客户端使用 *stub(存根)*将请求发送到服务器,并等待响应返回,就像普通函数调用一样。
// 获取给定点的要素。
rpc GetFeature(Point) returns (Feature) {}
  • 服务端流式 RPC:客户端向服务器发送请求并获得一个流以读取一系列消息。客户端从返回的流中读取,直到没有更多的消息为止。如例子所示,通过在响应类型之前放置 stream 关键字来指定服务器端流式方法。
// 获取给定矩形范围内的要素。
// 结果以流的形式返回,而不是即时返回,因为矩形可能覆盖一个大区域并且包含大量要素。
rpc ListFeatures(Rectangle) returns (stream Feature) {}
  • 客户端流式RPC:客户端使用提供的流编写一系列消息并将它们发送到服务器。一旦客户端完成编写消息,它就会等待服务器读取所有消息并返回其响应。通过在请求类型之前放置 stream 关键字来指定客户端流式方法。
// 记录遍历路线中的点。当遍历完成时返回 RouteSummary。
rpc RecordRoute(stream Point) returns (RouteSummary) {}
  • 双向流式RPC:双方使用读写流发送一系列消息。这两个流操作是独立的,因此客户端和服务端可以按任何顺序读取和写入:例如,服务端可以等待接收所有客户端消息然后编写其响应,或者它可以交替读取消息然后写入消息,或者使用其他组合方式。每个流中消息是有序的。通过在请求和响应之前都放置 stream 关键字来指定此类型的方法。
// 在遍历路线时接收 RouteNote ,同时也发送的一系列 RouteNote。
rpc RouteChat(stream RouteNote) returns (stream RouteNote) {}

我们的 .proto 文件还包含了用于 rpc 方法使用的所有请求和响应类型的 protocol buffer message(消息)类型定义。

例如,这是 Point 消息类型:

// 点被表示为纬度经度对,以E7表示形式(度乘以10**7并四舍五入到最接近的整数)。
// 纬度应在 +/- 90 度的范围内,经度应在 +/- 180 度的范围内(包含边界数值)。
message Point {
  int32 latitude = 1;
  int32 longitude = 2;
}