You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
This tutorial shows you how to write a simple server and client in C++ using gRPC's asynchronous/non-blocking APIs. It assumes you are already familiar with writing simple synchronous gRPC code, as described in [gRPC Basics: C++](/docs/tutorials/basic/c.html). The example used in this tutorial follows on from the basic [Greeter example](https://github.com/grpc/grpc/tree/{{ site.data.config.grpc_release_branch }}/examples/cpp/helloworld) we used in the [overview](/docs/index.html). You'll find it along with installation instructions in [grpc/examples/cpp/helloworld](https://github.com/grpc/grpc/tree/{{ site.data.config.grpc_release_branch }}/examples/cpp/helloworld).
7
+
This tutorial shows you how to write a simple server and client in C++ using
8
+
gRPC's asynchronous/non-blocking APIs. It assumes you are already familiar with
9
+
writing simple synchronous gRPC code, as described in [gRPC Basics:
10
+
C++](/docs/tutorials/basic/c.html). The example used in this tutorial follows on
11
+
from the basic [Greeter example](https://github.com/grpc/grpc/tree/{{
12
+
site.data.config.grpc_release_branch }}/examples/cpp/helloworld) we used in the
13
+
[overview](/docs/index.html). You'll find it along with installation
gRPC uses the [`CompletionQueue`](http://www.grpc.io/grpc/cpp/classgrpc_1_1_completion_queue.html) API for asynchronous operations. The basic work flow
API for asynchronous operations. The basic work flow
14
25
is as follows:
15
26
16
27
- bind a `CompletionQueue` to an RPC call
@@ -20,7 +31,12 @@ is as follows:
20
31
21
32
## Async client
22
33
23
-
To use an asynchronous client to call a remote method, you first create a channel and stub, just as you do in a [synchronous client](https://github.com/grpc/grpc/blob/{{ site.data.config.grpc_release_branch }}/examples/cpp/helloworld/greeter_client.cc). Once you have your stub, you do the following to make an asynchronous call:
34
+
To use an asynchronous client to call a remote method, you first create a
35
+
channel and stub, just as you do in a [synchronous
36
+
client](https://github.com/grpc/grpc/blob/{{
37
+
site.data.config.grpc_release_branch
38
+
}}/examples/cpp/helloworld/greeter_client.cc). Once you have your stub, you do
39
+
the following to make an asynchronous call:
24
40
25
41
- Initiate the RPC and create a handle for it. Bind the RPC to a
26
42
`CompletionQueue`.
@@ -50,12 +66,16 @@ To use an asynchronous client to call a remote method, you first create a channe
50
66
}
51
67
```
52
68
53
-
You can see the complete client example in [greeter_async_client.cc](https://github.com/grpc/grpc/blob/{{ site.data.config.grpc_release_branch }}/examples/cpp/helloworld/greeter_async_client.cc).
The server implementation requests an RPC call with a tag and then waits for the
58
-
completion queue to return the tag. The basic flow for handling an RPC asynchronously is:
77
+
completion queue to return the tag. The basic flow for handling an RPC
78
+
asynchronously is:
59
79
60
80
- Build a server exporting the async service
61
81
@@ -104,8 +124,10 @@ completion queue to return the tag. The basic flow for handling an RPC asynchron
104
124
}
105
125
```
106
126
107
-
This basic flow, however, doesn't take into account the server handling multiple requests concurrently. To deal with this, our complete async server example uses a `CallData` object to
108
-
maintain the state of each RPC, and uses the address of this object as the unique tag for the call.
127
+
This basic flow, however, doesn't take into account the server handling multiple
128
+
requests concurrently. To deal with this, our complete async server example uses
129
+
a `CallData` object to maintain the state of each RPC, and uses the address of
130
+
this object as the unique tag for the call.
109
131
110
132
```
111
133
class CallData {
@@ -153,8 +175,8 @@ maintain the state of each RPC, and uses the address of this object as the uniqu
153
175
}
154
176
```
155
177
156
-
For simplicity the server only uses one completion queue for all events, and runs a
157
-
main loop in `HandleRpcs` to query the queue:
178
+
For simplicity the server only uses one completion queue for all events, and
179
+
runs a main loop in `HandleRpcs` to query the queue:
158
180
159
181
```
160
182
void HandleRpcs() {
@@ -173,7 +195,29 @@ main loop in `HandleRpcs` to query the queue:
173
195
}
174
196
```
175
197
176
-
You can see our complete server example in [greeter_async_server.cc](https://github.com/grpc/grpc/blob/{{ site.data.config.grpc_release_branch }}/examples/cpp/helloworld/greeter_async_server.cc).
198
+
### Shutting Down the Server
199
+
We've been using a completion queue to get the async notifications. Care must be
200
+
taken to shut it down *after* the server has also been shut down.
177
201
202
+
Remember we got our completion queue instance `cq_` in `ServerImpl::Run()` by
203
+
running `cq_ = builder.AddCompletionQueue()`. Looking at
204
+
`ServerBuilder::AddCompletionQueue`'s documentation we see that
178
205
206
+
> ... Caller is required to shutdown the server prior to shutting down the
207
+
> returned completion queue.
179
208
209
+
Refer to `ServerBuilder::AddCompletionQueue`'s full docstring for more details.
210
+
What this means in our example is that `ServerImpl's` destructor looks like:
211
+
212
+
```
213
+
~ServerImpl() {
214
+
server_->Shutdown();
215
+
// Always shutdown the completion queue after the server.
0 commit comments