grpcpython异步实现_gRPC官⽅⽂档中⽂版
# gRPC 基础: C#
本教程提供了 C# 程序员如何使⽤ gRPC 的指南。
通过学习教程中例⼦,你可以学会如何:
- 在⼀个 .proto ⽂件内定义服务。
- ⽤ protocol buffer 编译器⽣成服务器和客户端代码。
- 使⽤ gRPC 的 C# API 为你的服务实现⼀个简单的客户端和服务器。
这算不上是⼀个在 C# 中使⽤ gRPC 的综合指南:以后会有更多的参考⽂档。
## 为什么使⽤ gRPC?
我们的例⼦是⼀个简单的路由映射的应⽤,它允许客户端获取路由特性的信息,⽣成路由的总结,以及交互路由信息,如服务器和其他客户端的流量更新。
有了 gRPC, 我们可以⼀次性的在⼀个 .proto ⽂件中定义服务并使⽤任何⽀持它的语⾔去实现客户端和服务器,反过来,它们可以在各种环境中,从Google的服务器到你⾃⼰的平板电脑—— gRPC 帮你解决了不同语⾔间通信的复杂性以及环境的不同。使⽤ protocol
buffers 还能获得其他好处,包括⾼效的序列号,简单的 IDL 以及容易进⾏的接⼝更新。
## 例⼦代码和设置
```
```
本教程的所有⽂件都在`examples/csharp/route_guide`⽬录下。
从 Visual Studio (或者 Linux 上的 Monodevelop)打开解决⽅案 `examples/csharp/route_guide/RouteGuide.sln`。
如果系统是Windows,除了打开解决⽅案⽂件之外,你应当不⽤多做任何事情。所有你需要的依赖都会在都会在构建解决⽅案的过程中通过 `Grpc` NuGet 包⾃动恢复。
## 定义服务
要定义⼀个服务,你必须在你的 .proto ⽂件中指定 `service`:
```protobuf
service RouteGuide {
...
}
```
然后在你的服务中定义 `rpc` ⽅法,指定请求的和响应类型。gRPC允 许你定义4种类型的 service ⽅法,在 `RouteGuide` 服务中都有使⽤:
- ⼀个 *简单 RPC* , 客户端使⽤存根发送请求到服务器并等待响应返回,就像平常的函数调⽤⼀样。
```protobuf
// Obtains the feature at a given position.
rpc GetFeature(Point) returns (Feature) {}
```
- ⼀个 *服务器端流式 RPC* , 客户端发送请求到服务器,拿到⼀个流去读取返回的消息序列。 客户端读取返回的流,直到⾥⾯没有任何消息。从例⼦中可以看出,通过在 *响应* 类型前插⼊ `stream` 关键字,可以指定⼀个服务器端的流⽅法。
```protobuf
// Obtains the Features available within the given Rectangle. Results are
// streamed rather than returned at once (e.g. in a response message with a
// repeated field), as the rectangle may cover a large area and contain a
// huge number of features.
rpc ListFeatures(Rectangle) returns (stream Feature) {}
```
- ⼀个 *客户端流式 RPC* , 客户端写⼊⼀个消息序列并将其发送到服务器,同样也是使⽤流。⼀旦客
户端完成写⼊消息,它等待服务器完成读取返回它的响应。通过在 *请求* 类型前指定 `stream` 关键字来指定⼀个客户端的流⽅法。
```protobuf
// Accepts a stream of Points on a route being traversed, returning a
// RouteSummary when traversal is completed.
rpc RecordRoute(stream Point) returns (RouteSummary) {}
```
- ⼀个 *双向流式 RPC* 是双⽅使⽤读写流去发送⼀个消息序列。两个流独⽴操作,因此客户端和服务器可以以任意喜欢的顺序读写:⽐如, 服务器可以在写⼊响应前等待接收所有的客户端消息,或者可以交替的读取和写⼊消息,或者其他读写的组合。 每个流中的消息顺序被预留。你可以通过在请求和响应前加 `stream` 关键字去制定⽅法的类型。
```protobuf
// Accepts a stream of RouteNotes sent while a route is being traversed,
// while receiving other RouteNotes (e.g. from other users).
rpc RouteChat(stream RouteNote) returns (stream RouteNote) {}
```
我们的 .proto ⽂件也包含了所有请求的 protocol buffer 消息类型定义以及在服务⽅法中使⽤的响应类型-⽐如,下⾯的`Point`消息类型:
```protobuf
// Points are represented as latitude-longitude pairs in the E7 representation
// (degrees multiplied by 10**7 and rounded to the nearest integer).
writeline和write的区别python// Latitudes should be in the range +/- 90 degrees and longitude should be in
// the range +/- 180 degrees (inclusive).
message Point {
int32 latitude = 1;
int32 longitude = 2;
}
```
## ⽣成客户端和服务器端代码
接下来我们需要从 .proto 的服务定义中⽣成 gRPC 客户端和服务器端的接⼝。我们通过 protocol buffer 的编译器 `protoc` 以及⼀个特殊的 gRPC C# 插件来完成。
如果你想⾃⼰运⾏,请确保你已经安装了 protoc 和 gRPC 的 C# 插件。运⾏的指令因操作系统⽽异:
- 对于 Windows 系统来说,`Grpc.Tools` 和 `Google.Protobuf` 的 NuGet 包包含了⽣成代码所需要的⼆进制⽂件。
以上都完成后,你就可以⽣成下⾯的 C# 代码:
- 我们使⽤ `Google.Protobuf` NuGet 包的`` 和 `Grpc.Tools` NuGet 包的 `grpc_` (都在 `tools` ⽬录下)在 Windows 上⽣成代码。
⼀般来说,你需要⾃⼰添加 `Grpc.Tools` 包到解决⽅案中,但在本教程中,它已经帮你完成了。下⾯的命令应当从
`examples/csharp/route_guide` ⽬录运⾏:
```
> packages\Google.Protobuf.3.0.0-alpha4\ -I../../protos --csharp_out RouteGuide --grpc_out RouteGuide --plugin=protoc-gen-grpc=packages\Grpc.Tools.0.7.0\tools\grpc_ ../../protos/route_guide.proto
```
- 在 Linux 或者 OS X 系统,我们可以⽤ Linuxbrew/Homebrew 安装 `protoc` 和 `grpc_csharp_plugin` 依赖。从 route_guide ⽬录运⾏下⾯的命令:
```
$ protoc -I../../protos --csharp_out RouteGuide --grpc_out RouteGuide --plugin=`which grpc_csharp_plugin`
../../protos/route_guide.proto
```
根据操作系统的不同,运⾏对应的命令去重新在 RouteGuide ⽬录⽣成下⾯的⽂件:
- `RouteGuide/RouteGuide.cs` 定义了⼀个命名空间 `Routeguide`
- 它包含了所有填充,序列化的 protocol buffer 代码以及获取我们的请求和响应的类型。
- `RouteGuide/RouteGuideGrpc.cs`, 提供了存根和服务类
- 定义 RouteGuide 服务实现时继承的接⼝ `RouteGuide.IRouteGuide`
- ⽤来访问远程 RouteGuide 实例的类 `RouteGuide.RouteGuideClient`
## 创建服务器
⾸先来看看我们如何创建⼀个 `RouteGuide` 服务器。如果你只对创建 gRPC 客户端感兴趣,你可以跳过这个部分,直接到[创建客户端] (#client) (当然你也可能发现它也很有意思)。
让 `RouteGuide` 服务⼯作有两个部分:
- 实现我们服务定义的⽣成的服务接⼝:做我们的服务的实际的“⼯作”。
- 运⾏⼀个 gRPC 服务器,监听来⾃客户端的请求并返回服务的响应。
### 实现RouteGuide
我们可以看出,服务器有⼀个实现了⽣成的 `RouteGuide.IRouteGuide` 接⼝的 `RouteGuideImpl` 类:
```csharp
// RouteGuideImpl provides an implementation of the RouteGuide service.
public class RouteGuideImpl : RouteGuide.IRouteGuide
```
#### 简单RPC
`RouteGuideImpl` 实现了所有的服务⽅法。让我们先来看看最简单的类型 `GetFeature`,它从客户端拿到⼀个 `Point` 然后将对应的从数据库中取得的特征信息置于 `Feature` 内返回给客户端。
```csharp
public Task GetFeature(Point request, Grpc.Core.ServerCallContext context)
{
return Task.FromResult(CheckFeature(request));
}
```
为了 RPC,⽅法被传⼊⼀个上下⽂(alpha 版的时候为空),指客户端的 `Point` protocol buffer 请求,返回⼀个 `Feature` protocol buffer。在⽅法中,我们⽤适当的信息创建 `Feature` 然后返回。为了允许异步的实现,⽅法返回 `Task` ⽽不仅是 `Feature`。你可以随意的同步执⾏你的计算,并在完成后返回结果,就像我们在例⼦中做的⼀样。
#### 服务器端流式 RPC
现在让我们来看看稍微复杂点的 —— ⼀个流式 RPC。`ListFeatures` 是⼀个服务器端的流式 RPC,所以我们需要给客户端发回多个
`Feature` protocol buffer。
```csharp
// in RouteGuideImpl
public async Task ListFeatures(Rectangle request,
Grpc.Core.IServerStreamWriter responseStream,
Grpc.Core.ServerCallContext context)
{
var responses = features.FindAll( (feature) => feature.Exists() && request.Contains(feature.Location) );
foreach (var response in responses)
{
await responseStream.WriteAsync(response);
}
}
```
如你所见,这⾥的请求对象是⼀个 `Rectangle`,客户端期望从中到 `Feature`,但是我们需要使⽤异步⽅法 `WriteAsync` 写⼊响应到 `IServerStreamWriter` 异步流⽽不是⼀个简单的响应。
#### 客户端流 RPC
```csharp
public async Task RecordRoute(Grpc.Core.IAsyncStreamReader requestStream,
Grpc.Core.ServerCallContext context)
{
int pointCount = 0;
int featureCount = 0;
int distance = 0;
Point previous = null;
var stopwatch = new Stopwatch();
stopwatch.Start();
while (await requestStream.MoveNext())
{
var point = requestStream.Current;
pointCount++;
if (CheckFeature(point).Exists())
{
featureCount++;
}
if (previous != null)
{
distance += (int) previous.GetDistance(point);
}
previous = point;
}
stopwatch.Stop();
return new RouteSummary
{
PointCount = pointCount,
FeatureCount = featureCount,
Distance = distance,
ElapsedTime = (int)(stopwatch.ElapsedMilliseconds / 1000)
};
}
```
#### 双向流 RPC
最后,让我们来看看双向流 RPC `RouteChat`。
```csharp
public async Task RouteChat(Grpc.Core.IAsyncStreamReader requestStream,

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。