mirror of https://github.com/grpc/grpc.git
commit
29ea501ce3
5 changed files with 353 additions and 282 deletions
@ -1,81 +1,393 @@ |
|||||||
# gRPC Hello World Tutorial |
# Getting started |
||||||
|
|
||||||
## TODO: move this to the tutorial sub-folder |
## TODO: move this to the tutorial sub-folder |
||||||
|
|
||||||
A great way to get introduced to gRPC is to work through this tutorial, which |
Welcome to the developer documentation for gRPC, a language-neutral, |
||||||
walks you through the construction of a simple client and server and introduces |
platform-neutral remote procedure call (RPC) system developed at Google. |
||||||
various features of gRPC. |
|
||||||
|
|
||||||
When you finish the tutorial, you will be able to |
This document introduces you to gRPC with a quick overview and a simple |
||||||
|
Hello World example. More documentation is coming soon! |
||||||
|
|
||||||
- Create a protobuf schema that defines a simple RPC service. |
## What is gRPC? |
||||||
- Create a Java server that implements the schema interface. |
|
||||||
- Create a Java client that accesses the server. |
## TODO: basic conceptual intro (anything more in-depth will go in gRPC Concepts doc) |
||||||
- Create a Go client that accesses the Java server. |
|
||||||
- Update the service with advanced features like RPC streaming. |
|
||||||
|
|
||||||
# Get Started |
<a name="hello"></a> |
||||||
|
## Hello gRPC! |
||||||
|
|
||||||
The rest of this page explains how you can set up your local machine for development. |
Now that you know a bit more about gRPC, the easiest way to see how it |
||||||
If you just want to read the tutorial, you can go straight to the next step: [Step - 0](Step_0.md) |
works is to look at a simple example. Our Hello World walks you through the |
||||||
|
construction of a simple gRPC client-server application, showing you how to: |
||||||
|
|
||||||
|
- Create a protobuf schema that defines a simple RPC service with a single |
||||||
|
Hello World method. |
||||||
|
- Create a Java server that implements the schema interface. |
||||||
|
- Create a Java client that accesses the Java server. |
||||||
|
- Create a Go client that accesses the same Java server. |
||||||
|
- Update the service with more advanced features like RPC streaming. |
||||||
|
|
||||||
# Working with the code |
The complete code for the example is available in the `grpc-common` GitHub repository. You can |
||||||
|
work along with the example and hack on the code in the comfort of your own |
||||||
|
computer, giving you hands-on practice of really writing |
||||||
|
gRPC code. We use the Git versioning system for source code management: |
||||||
|
however, you don't need to know anything about Git to follow along other |
||||||
|
than how to install and run a few git commands. |
||||||
|
|
||||||
You can follow along with this tutorial and hack on the code in the comfort of |
This is an introductory example rather than a comprehensive tutorial, so |
||||||
your own computer. This way you can get hands-on practice of really writing |
don't worry if you're not a Go or |
||||||
gRPC code. |
Java developer - complete tutorials and reference documentation for all gRPC |
||||||
|
languages are coming soon. |
||||||
|
|
||||||
The tutorial relies on the use of the Git versioning system for source code |
<a name="setup"></a> |
||||||
management. You don't need to know anything about Git to follow the tutorial |
### Setup |
||||||
other than how to install and run a few git commands. |
|
||||||
|
|
||||||
# Install Git |
The rest of this page explains how to set up your local machine to work with |
||||||
|
the example code. |
||||||
|
If you just want to read the example, you can go straight to the [next step](#servicedef). |
||||||
|
|
||||||
|
#### Install Git |
||||||
|
|
||||||
You can download and install Git from http://git-scm.com/download. Once |
You can download and install Git from http://git-scm.com/download. Once |
||||||
installed you should have access to the git command line tool. The main |
installed you should have access to the git command line tool. The main |
||||||
commands that you will need to use are: |
commands that you will need to use are: |
||||||
|
|
||||||
- git clone ... : clone a remote repository onto your local machine |
- git clone ... : clone a remote repository onto your local machine |
||||||
- git checkout ... : check out a particular branch or a tagged version of the code to hack on |
- git checkout ... : check out a particular branch or a tagged version of |
||||||
|
the code to hack on |
||||||
|
|
||||||
# Download grpc-helloworld |
#### Get the source code |
||||||
|
|
||||||
Clone the grpc-helloword repository located at GitHub by running the following command: |
The example code for this and our other examples lives in the `grpc-common` GitHub repository. Clone this repository to your local machine by running the |
||||||
|
following command: |
||||||
|
|
||||||
``` |
``` |
||||||
git clone https://github.com/google/grpc-helloworld.git |
git clone https://github.com/google/grpc-common.git |
||||||
``` |
``` |
||||||
|
|
||||||
Change your current directory to grpc-helloworld |
Change your current directory to grpc-common/java |
||||||
|
|
||||||
``` |
``` |
||||||
cd grpc-helloworld |
cd grpc-common/java |
||||||
``` |
``` |
||||||
|
|
||||||
# Install Java 8 |
#### Install Java 8 |
||||||
|
|
||||||
Java gRPC is designed to work with both Java 7 and Java 8. For simplicity, |
Java gRPC is designed to work with both Java 7 and Java 8 - our example uses |
||||||
the example assumes that Java 8 is installed. See |
Java 8. See |
||||||
[Install Java 8](http://docs.oracle.com/javase/8/docs/technotes/guides/install/install_overview.html) |
[Install Java |
||||||
for instructions. |
8](http://docs.oracle.com/javase/8/docs/technotes/guides/install/install_overview.html) |
||||||
|
for instructions if you need to install Java 8. |
||||||
|
|
||||||
# Install Maven |
#### Install Maven |
||||||
|
|
||||||
To simplify building and the managing of gRPC's dependencies, the Java client |
To simplify building and managing gRPC's dependencies, the Java client |
||||||
are server are structured as a standard [Maven](http://maven.apache.org/guides/getting-started/) |
and server are structured as a standard |
||||||
project. See [Install Maven](http://maven.apache.org/users/index.html) for instructions. |
[Maven](http://maven.apache.org/guides/getting-started/) |
||||||
|
project. See [Install Maven](http://maven.apache.org/users/index.html) |
||||||
|
for instructions. |
||||||
|
|
||||||
|
|
||||||
# Install Go 1.4 |
#### Install Go 1.4 |
||||||
|
|
||||||
Go gRPC requires Go 1.4, the latest version of Go. See |
Go gRPC requires Go 1.4, the latest version of Go. See |
||||||
[Install Go](https://golang.org/doc/install) for instructions. |
[Install Go](https://golang.org/doc/install) for instructions. |
||||||
|
|
||||||
# (optional) Install protoc |
#### (optional) Install protoc |
||||||
|
|
||||||
gRPC uses the latest version of the protocol buffer compiler, protoc. |
gRPC uses the latest version of the [protocol |
||||||
|
buffer](https://developers.google.com/protocol-buffers/docs/overview) |
||||||
|
compiler, protoc. |
||||||
|
|
||||||
For following this tutorial, the protoc is not strictly necessary, as all the |
Having protoc installed isn't strictly necessary to follow along with this |
||||||
generated code is checked into the Git repository. If you want to experiment |
example, as all the |
||||||
|
generated code is checked into the Git repository. However, if you want |
||||||
|
to experiment |
||||||
with generating the code yourself, download and install protoc from its |
with generating the code yourself, download and install protoc from its |
||||||
[Git repo](https://github.com/google/protobuf) |
[Git repo](https://github.com/google/protobuf) |
||||||
|
|
||||||
|
<a name="servicedef"></a> |
||||||
|
### Defining a service |
||||||
|
|
||||||
|
The first step in creating our example is to define a *service*: an RPC |
||||||
|
service specifies the methods that can be called remotely with their parameters |
||||||
|
and return types. In gRPC, we use the protocol buffers interface definition |
||||||
|
language (IDL) to define our service methods, and the parameters and return |
||||||
|
types are defined as protocol buffer message types. Both the client and the |
||||||
|
server use interface code generated from the service definition. If you're not |
||||||
|
familiar with protocol buffers, you can find out more in the [Protocol Buffers |
||||||
|
Developer Guide](https://developers.google.com/protocol-buffers/docs/overview). |
||||||
|
|
||||||
|
Here's our example service definition, defined using protocol buffers IDL in |
||||||
|
[helloworld.proto](java/src/main/proto/helloworld.proto) _should we link to the version in the Java subdirectory or the one in the common protos directory?_. The `Greeting` service |
||||||
|
has one method, `hello`, that lets the server receive a single `HelloRequest` |
||||||
|
message from the remote client containing the user's name, then send back |
||||||
|
a greeting in a `HelloReply`. |
||||||
|
|
||||||
|
``` |
||||||
|
syntax = "proto3"; |
||||||
|
|
||||||
|
option java_package = "ex.grpc"; |
||||||
|
|
||||||
|
package helloworld; |
||||||
|
|
||||||
|
// The request message containing the user's name. |
||||||
|
message HelloRequest { |
||||||
|
optional string name = 1; |
||||||
|
} |
||||||
|
|
||||||
|
// The response message containing the greetings |
||||||
|
message HelloReply { |
||||||
|
optional string message = 1; |
||||||
|
} |
||||||
|
|
||||||
|
// The greeting service definition. |
||||||
|
service Greeting { |
||||||
|
|
||||||
|
// Sends a greeting |
||||||
|
rpc hello (HelloRequest) returns (HelloReply) { |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
``` |
||||||
|
|
||||||
|
<a name="generating"></a> |
||||||
|
### Generating gRPC code |
||||||
|
|
||||||
|
Once we've defined our service, we use the protocol buffer compiler |
||||||
|
`protoc` to generate the special client and server code we need to create |
||||||
|
our application - right now we're going to generate Java code, though you |
||||||
|
can generate gRPC code in any gRPC-supported language (as you'll see later |
||||||
|
in this example). The generated code contains both stub code for clients to |
||||||
|
use and an abstract interface for servers to implement, both with the method |
||||||
|
defined in our `Greeting` service. A stub is code that initiates contact |
||||||
|
with a gRPC service running remotely via the internet. [can probably define |
||||||
|
this up in "what is gRPC"?] |
||||||
|
|
||||||
|
(If you didn't install `protoc` on your system and are working along with |
||||||
|
the example, you can skip this step and move |
||||||
|
onto the next one where we examine the generated code.) |
||||||
|
|
||||||
|
As this is our first time using gRPC, we need to build the protobuf plugin that generates our RPC |
||||||
|
classes. By default `protoc` just generates code for reading and writing |
||||||
|
protocol buffers, so you need to use plugins to add additional features |
||||||
|
to generated code. As we're creating Java code, we use the gRPC Java plugin. |
||||||
|
|
||||||
|
To build the plugin: |
||||||
|
|
||||||
|
```sh |
||||||
|
$ pushd external/grpc_java |
||||||
|
$ make java_plugin |
||||||
|
$ popd |
||||||
|
``` |
||||||
|
|
||||||
|
To use it to generate the code: |
||||||
|
|
||||||
|
```sh |
||||||
|
$ mkdir -p src/main/java |
||||||
|
$ protoc -I . helloworld.proto |
||||||
|
--plugin=protoc-gen-grpc=external/grpc_java/bins/opt/java_plugin \ |
||||||
|
--grpc_out=src/main/java \ |
||||||
|
--java_out=src/main/java |
||||||
|
``` |
||||||
|
|
||||||
|
This generates the following classes, which contain all the generated code we need to create our example: |
||||||
|
|
||||||
|
- [`Helloworld.java`](java/src/main/java/ex/grpc/Helloworld.java), which has all the protocol buffer code to populate, serialize, and retrieve our `HelloRequest` and `HelloReply` message types |
||||||
|
- [`GreetingsGrpc.java`](java/src/main/java/ex/grpc/GreetingsGrpc.java), which contains (along with some other useful code): |
||||||
|
- an interface for `Greetings` servers to implement |
||||||
|
|
||||||
|
```java |
||||||
|
public static interface Greetings { |
||||||
|
|
||||||
|
public void hello(ex.grpc.Helloworld.HelloRequest request, |
||||||
|
com.google.net.stubby.stub.StreamObserver<ex.grpc.Helloworld.HelloReply> responseObserver); |
||||||
|
} |
||||||
|
``` |
||||||
|
|
||||||
|
- _stub_ classes that clients can use to talk to a `Greetings` server. |
||||||
|
|
||||||
|
```java |
||||||
|
public static class GreetingsStub extends |
||||||
|
com.google.net.stubby.stub.AbstractStub<GreetingsStub, GreetingsServiceDescriptor> |
||||||
|
implements Greetings { |
||||||
|
... |
||||||
|
} |
||||||
|
``` |
||||||
|
|
||||||
|
<a name="server"></a> |
||||||
|
### Writing a server |
||||||
|
|
||||||
|
Now let's write some code! First we'll create a server application to implement our service. Note that we're not going to go into a lot of detail about how to create a server in this section More detailed information will be in the tutorial for your chosen language (coming soon). |
||||||
|
|
||||||
|
Our server application has two classes: |
||||||
|
|
||||||
|
- a simple service implementation [GreetingsImpl.java](java/src/main/java/ex/grpc/GreetingsImpl.java). |
||||||
|
|
||||||
|
- a server that hosts the service implementation and allows access over the network: [GreetingsServer.java](src/main/java/ex/grpc/GreetingsServer.java). |
||||||
|
|
||||||
|
#### Service implementation |
||||||
|
|
||||||
|
[GreetingsImpl.java](java/src/main/java/ex/grpc/GreetingsImpl.java) |
||||||
|
implements the behaviour we require of our GreetingService. There are a |
||||||
|
number of important features of gRPC being used here: |
||||||
|
|
||||||
|
```java |
||||||
|
public void hello(Helloworld.HelloRequest req, |
||||||
|
StreamObserver<Helloworld.HelloReply> responseObserver) { |
||||||
|
Helloworld.HelloReply reply = Helloworld.HelloReply.newBuilder().setMessage( |
||||||
|
"Hello " + req.getName()).build(); |
||||||
|
responseObserver.onValue(reply); |
||||||
|
responseObserver.onCompleted(); |
||||||
|
} |
||||||
|
``` |
||||||
|
|
||||||
|
- it provides a class `GreetingsImpl` that implements a generated interface `GreetingsGrpc.Greetings` |
||||||
|
- `GreetingsGrpc.Greetings` declares the method `hello` that was declared in the proto [IDL](src/main/proto/helloworld.proto) |
||||||
|
- `hello's` signature is typesafe: |
||||||
|
hello(Helloworld.HelloRequest req, StreamObserver<Helloworld.HelloReply> responseObserver) |
||||||
|
- `hello` takes two parameters: |
||||||
|
`Helloworld.HelloRequest`: the request |
||||||
|
`StreamObserver<Helloworld.HelloReply>`: a response observer, an interface to be called with the response value |
||||||
|
- to complete the call |
||||||
|
- the return value is constructed |
||||||
|
- the responseObserver.onValue() is called with the response |
||||||
|
- responseObserver.onCompleted() is called to indicate that no more work will done on the RPC. |
||||||
|
|
||||||
|
|
||||||
|
#### Server implementation |
||||||
|
|
||||||
|
[GreetingsServer.java](src/main/java/ex/grpc/GreetingsServer.java) shows the |
||||||
|
other main feature required to provde the gRPC service; how to allow a service |
||||||
|
implementation to be accessed from the network. |
||||||
|
|
||||||
|
```java |
||||||
|
private void start() throws Exception { |
||||||
|
server = NettyServerBuilder.forPort(port) |
||||||
|
.addService(GreetingsGrpc.bindService(new GreetingsImpl())) |
||||||
|
.build(); |
||||||
|
server.startAsync(); |
||||||
|
server.awaitRunning(5, TimeUnit.SECONDS); |
||||||
|
} |
||||||
|
|
||||||
|
``` |
||||||
|
|
||||||
|
- it provides a class `GreetingsServer` that holds a `ServerImpl` that will run the server |
||||||
|
- in the `start` method, `GreetingServer` binds the `GreetingsService` implementation to a port and begins running it |
||||||
|
- there is also a `stop` method that takes care of shutting down the service and cleaning up when the program exits |
||||||
|
|
||||||
|
#### Build it |
||||||
|
|
||||||
|
Once we've implemented everything, we use Maven to build the server: |
||||||
|
|
||||||
|
``` |
||||||
|
$ mvn package |
||||||
|
``` |
||||||
|
|
||||||
|
We'll look at using a client to access the server in the next section. |
||||||
|
|
||||||
|
<a name="client"></a> |
||||||
|
### Writing a client |
||||||
|
|
||||||
|
Client-side gRPC is pretty simple. In this step, we'll use the generated code to write a simple client that can access the `Greetings` server we created in the previous section. You can see the complete client code in [GreetingsClient.java](src/main/java/ex/grpc/GreetingsClient.java). |
||||||
|
|
||||||
|
Again, we're not going to go into much detail about how to implement a client - we'll leave that for the tutorial. |
||||||
|
|
||||||
|
#### Connecting to the service |
||||||
|
|
||||||
|
. The internet address |
||||||
|
is configured in the client constructor. gRPC Channel is the abstraction over |
||||||
|
transport handling; its constructor accepts the host name and port of the |
||||||
|
service. The channel in turn is used to construct the Stub. |
||||||
|
|
||||||
|
|
||||||
|
```java |
||||||
|
private final ChannelImpl channel; |
||||||
|
private final GreetingGrpc.GreetingBlockingStub blockingStub; |
||||||
|
|
||||||
|
public HelloClient(String host, int port) { |
||||||
|
channel = NettyChannelBuilder.forAddress(host, port) |
||||||
|
.negotiationType(NegotiationType.PLAINTEXT) |
||||||
|
.build(); |
||||||
|
blockingStub = GreetingGrpc.newBlockingStub(channel); |
||||||
|
} |
||||||
|
|
||||||
|
``` |
||||||
|
|
||||||
|
#### Obtaining a greeting |
||||||
|
|
||||||
|
The greet method uses the stub to contact the service and obtain a greeting. |
||||||
|
It: |
||||||
|
- constructs a request |
||||||
|
- obtains a reply from the stub |
||||||
|
- prints out the greeting |
||||||
|
|
||||||
|
|
||||||
|
```java |
||||||
|
public void greet(String name) { |
||||||
|
logger.debug("Will try to greet " + name + " ..."); |
||||||
|
try { |
||||||
|
Helloworld.HelloRequest request = Helloworld.HelloRequest.newBuilder().setName(name).build(); |
||||||
|
Helloworld.HelloReply reply = blockingStub.hello(request); |
||||||
|
logger.info("Greeting: " + reply.getMessage()); |
||||||
|
} catch (RuntimeException e) { |
||||||
|
logger.log(Level.WARNING, "RPC failed", e); |
||||||
|
return; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
``` |
||||||
|
|
||||||
|
#### Running from the command line |
||||||
|
|
||||||
|
The main method puts together the example so that it can be run from a command |
||||||
|
line. |
||||||
|
|
||||||
|
```java |
||||||
|
/* Access a service running on the local machine on port 50051 */ |
||||||
|
HelloClient client = new HelloClient("localhost", 50051); |
||||||
|
String user = "world"; |
||||||
|
if (args.length > 1) { |
||||||
|
user = args[1]; |
||||||
|
} |
||||||
|
client.greet(user); |
||||||
|
|
||||||
|
``` |
||||||
|
|
||||||
|
#### Build the client |
||||||
|
|
||||||
|
This is the same as before: our client and server are part of the same maven |
||||||
|
package so the same command builds both. |
||||||
|
|
||||||
|
``` |
||||||
|
$ mvn package |
||||||
|
``` |
||||||
|
|
||||||
|
#### Notes |
||||||
|
|
||||||
|
- The client uses a blocking stub. This means that the RPC call waits for the |
||||||
|
server to respond, and will either return a response or raise an exception. |
||||||
|
|
||||||
|
- gRPC Java has other kinds of stubs that make non-blocking calls to the |
||||||
|
server, where the response is returned asynchronously. Usage of these stubs |
||||||
|
is a more advanced topic and will be described in later steps. |
||||||
|
|
||||||
|
<a name="run"></a> |
||||||
|
### Try it out! |
||||||
|
|
||||||
|
We've added simple shell scripts to simplifying running the examples. Now |
||||||
|
that they are built, you can run the server with: |
||||||
|
|
||||||
|
```sh |
||||||
|
$ ./run_greetings_server.sh |
||||||
|
``` |
||||||
|
|
||||||
|
and in another terminal window confirm that it receives a message. |
||||||
|
|
||||||
|
```sh |
||||||
|
$ ./run_greetings_client.sh |
||||||
|
``` |
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,41 +0,0 @@ |
|||||||
# Step-0: define a service |
|
||||||
|
|
||||||
This section presents an example of a simple service definition that receives |
|
||||||
a message from a remote client. The message contains the user's name and |
|
||||||
sends back a greeting to that person. |
|
||||||
|
|
||||||
It's shown below in full; it's actually contained in separate file. |
|
||||||
[helloworld.proto](src/main/proto/helloworld.proto). |
|
||||||
|
|
||||||
``` |
|
||||||
syntax = "proto3"; |
|
||||||
|
|
||||||
package helloworld; |
|
||||||
|
|
||||||
// The request message containing the user's name. |
|
||||||
message HelloRequest { |
|
||||||
optional string name = 1; |
|
||||||
} |
|
||||||
|
|
||||||
// The response message containing the greetings |
|
||||||
message HelloReply { |
|
||||||
optional string message = 1; |
|
||||||
} |
|
||||||
|
|
||||||
// The greeting service definition. |
|
||||||
service Greeting { |
|
||||||
|
|
||||||
// Sends a greeting |
|
||||||
rpc hello (HelloRequest) returns (HelloReply) { |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
``` |
|
||||||
|
|
||||||
The service stanza of the message is an example of protobuf service IDL |
|
||||||
(Interface Definition Language). Here, it defines a simple service that |
|
||||||
receives a request containing a name and returns a response containing a |
|
||||||
message. |
|
||||||
|
|
||||||
Next, in [Step - 1](Step_1.md), we'll use protoc to generate client code from |
|
||||||
this IDL. |
|
@ -1,32 +0,0 @@ |
|||||||
# Step-1: Generate a service client. |
|
||||||
|
|
||||||
In this step, we use protoc to generate the Java Stub classes. A Stub is the |
|
||||||
name gRPC uses for the code that initiates contact with a gRPC service running |
|
||||||
remotely via the internet. |
|
||||||
|
|
||||||
If you did not install protoc on your system, you can skip this step and move |
|
||||||
onto the next one where we examine the generated code. |
|
||||||
|
|
||||||
First, you'll need to build the protobuf plugin that generates the rpc |
|
||||||
classes. `protoc` uses other tools called plugins to add additional features |
|
||||||
to generated code. |
|
||||||
|
|
||||||
The gRPC Java Stub classes are created using a gRPC Java plugin, but first the |
|
||||||
plugin must be built and installed. |
|
||||||
|
|
||||||
To build the plugin: |
|
||||||
```sh |
|
||||||
$ pushd external/grpc_java |
|
||||||
$ make java_plugin |
|
||||||
$ popd |
|
||||||
``` |
|
||||||
|
|
||||||
To use it to generate the code: |
|
||||||
```sh |
|
||||||
$ protoc -I . helloworld.proto --plugin=protoc-gen-grpc=external/grpc_java/bins/opt/java_plugin \ |
|
||||||
--grpc_out=java/src/main/java \ |
|
||||||
--java_out=java/src/main/java |
|
||||||
``` |
|
||||||
|
|
||||||
Next, in [Step - 2](Step_2.md), we'll use the generated Stub implementation to |
|
||||||
write a client that uses the generated code to make a call to a service. |
|
@ -1,85 +0,0 @@ |
|||||||
# Step-2: Write a service client. |
|
||||||
|
|
||||||
This step uses the generated code to write a simple client to access the hello |
|
||||||
service. The full client is in [GreetingsClient.java](java/src/main/java/ex/grpc/GreetingsClient.java). |
|
||||||
|
|
||||||
|
|
||||||
## Configuring the service to connect to. |
|
||||||
|
|
||||||
The client contains uses a Stub to contact the service. The internet address |
|
||||||
is configured in the client constructor. gRPC Channel is the abstraction over |
|
||||||
transport handling; its constructor accepts the host name and port of the |
|
||||||
service. The channel in turn is used to construct the Stub. |
|
||||||
|
|
||||||
|
|
||||||
``` |
|
||||||
private final ChannelImpl channel; |
|
||||||
private final GreetingGrpc.GreetingBlockingStub blockingStub; |
|
||||||
|
|
||||||
public HelloClient(String host, int port) { |
|
||||||
channel = NettyChannelBuilder.forAddress(host, port) |
|
||||||
.negotiationType(NegotiationType.PLAINTEXT) |
|
||||||
.build(); |
|
||||||
blockingStub = GreetingGrpc.newBlockingStub(channel); |
|
||||||
} |
|
||||||
|
|
||||||
``` |
|
||||||
|
|
||||||
## Obtaining a greeting |
|
||||||
|
|
||||||
The greet method uses the stub to contact the service and obtain a greeting. |
|
||||||
It: |
|
||||||
- constructs a request |
|
||||||
- obtains a reply from the stub |
|
||||||
- prints out the greeting |
|
||||||
|
|
||||||
|
|
||||||
``` |
|
||||||
public void greet(String name) { |
|
||||||
logger.debug("Will try to greet " + name + " ..."); |
|
||||||
try { |
|
||||||
Helloworld.HelloRequest request = Helloworld.HelloRequest.newBuilder().setName(name).build(); |
|
||||||
Helloworld.HelloReply reply = blockingStub.hello(request); |
|
||||||
logger.info("Greeting: " + reply.getMessage()); |
|
||||||
} catch (RuntimeException e) { |
|
||||||
logger.log(Level.WARNING, "RPC failed", e); |
|
||||||
return; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
``` |
|
||||||
|
|
||||||
## Running from the command line |
|
||||||
|
|
||||||
The main method puts together the example so that it can be run from a command |
|
||||||
line. |
|
||||||
|
|
||||||
``` |
|
||||||
/* Access a service running on the local machine on port 50051 */ |
|
||||||
HelloClient client = new HelloClient("localhost", 50051); |
|
||||||
String user = "world"; |
|
||||||
if (args.length > 1) { |
|
||||||
user = args[1]; |
|
||||||
} |
|
||||||
client.greet(user); |
|
||||||
|
|
||||||
``` |
|
||||||
|
|
||||||
It can be built as follows. |
|
||||||
|
|
||||||
``` |
|
||||||
$ mvn package |
|
||||||
``` |
|
||||||
|
|
||||||
It can also be run, but doing so now would end up a with a failure as there is |
|
||||||
no server available yet. The [next step](Step_3.md), describes how to |
|
||||||
implement, build and run a server that supports the service description. |
|
||||||
|
|
||||||
## Notes |
|
||||||
|
|
||||||
- The client uses a blocking stub. This means that the RPC call waits for the |
|
||||||
server to respond, and will either return a response or raise an exception. |
|
||||||
|
|
||||||
- gRPC Java has other kinds of stubs that make non-blocking calls to the |
|
||||||
server, where the response is returned asynchronously. Usage of these stubs |
|
||||||
is a more advanced topic and will be described in later steps. |
|
@ -1,83 +0,0 @@ |
|||||||
# Step-3: Implement a server. |
|
||||||
|
|
||||||
This step extends the generated server skeleton code to write a simple server |
|
||||||
that provides the hello service. This introduces two new classes: |
|
||||||
|
|
||||||
- a service implementation [GreetingsImpl.java](java/src/main/java/ex/grpc/GreetingsImpl.java). |
|
||||||
|
|
||||||
- a server that hosts the service implementation and allows access over the network: [GreetingsServer.java](java/src/main/java/ex/grpc/GreetingsServer.java). |
|
||||||
|
|
||||||
## Service implementation |
|
||||||
|
|
||||||
[GreetingsImpl.java](java/src/main/java/ex/grpc/GreetingsImpl.java) |
|
||||||
implements the behaviour we require of our GreetingService. There are a |
|
||||||
number of important features of gRPC being used here: |
|
||||||
|
|
||||||
```java |
|
||||||
public void hello(Helloworld.HelloRequest req, |
|
||||||
StreamObserver<Helloworld.HelloReply> responseObserver) { |
|
||||||
Helloworld.HelloReply reply = Helloworld.HelloReply.newBuilder().setMessage( |
|
||||||
"Hello " + req.getName()).build(); |
|
||||||
responseObserver.onValue(reply); |
|
||||||
responseObserver.onCompleted(); |
|
||||||
} |
|
||||||
``` |
|
||||||
|
|
||||||
- it provides a class `GreetingsImpl` that implements a generated interface `GreetingsGrpc.Greetings` |
|
||||||
- `GreetingsGrpc.Greetings` declares the method `hello` that was declared in the proto [IDL](java/src/main/proto/helloworld.proto) |
|
||||||
- `hello's` signature is typesafe: |
|
||||||
hello(Helloworld.HelloRequest req, StreamObserver<Helloworld.HelloReply> responseObserver) |
|
||||||
- `hello` takes two parameters: |
|
||||||
`Helloworld.HelloRequest`: the request |
|
||||||
`StreamObserver<Helloworld.HelloReply>`: a response observer, an interface to be called with the response value |
|
||||||
- to complete the call |
|
||||||
- the return value is constructed |
|
||||||
- the responseObserver.onValue() is called with the response |
|
||||||
- responseObserver.onCompleted() is called to indicate that no more work will done on the RPC. |
|
||||||
|
|
||||||
|
|
||||||
## Server implementation |
|
||||||
|
|
||||||
[GreetingsServer.java](java/src/main/java/ex/grpc/GreetingsServer.java) shows the |
|
||||||
other main feature required to provde the gRPC service; how to allow a service |
|
||||||
implementation to be accessed from the network. |
|
||||||
|
|
||||||
```java |
|
||||||
private void start() throws Exception { |
|
||||||
server = NettyServerBuilder.forPort(port) |
|
||||||
.addService(GreetingsGrpc.bindService(new GreetingsImpl())) |
|
||||||
.build(); |
|
||||||
server.startAsync(); |
|
||||||
server.awaitRunning(5, TimeUnit.SECONDS); |
|
||||||
} |
|
||||||
|
|
||||||
``` |
|
||||||
|
|
||||||
- it provides a class `GreetingsServer` that holds a `ServerImpl` that will run the server |
|
||||||
- in the `start` method, `GreetingServer` binds the `GreetingsService` implementation to a port and begins running it |
|
||||||
- there is also a `stop` method that takes care of shutting down the service and cleaning up when the program exits |
|
||||||
|
|
||||||
## Build it |
|
||||||
|
|
||||||
This is the same as before: our client and server are part of the same maven |
|
||||||
package so the same command builds both. |
|
||||||
|
|
||||||
```sh |
|
||||||
$ cd java |
|
||||||
$ mvn package |
|
||||||
``` |
|
||||||
|
|
||||||
## Try them out |
|
||||||
|
|
||||||
We've added simple shell scripts to simplifying running the examples. Now |
|
||||||
that they are built, you can run the server with: |
|
||||||
|
|
||||||
```sh |
|
||||||
$ ./run_greetings_server.sh |
|
||||||
``` |
|
||||||
|
|
||||||
and in another terminal window confirm that it receives a message. |
|
||||||
|
|
||||||
```sh |
|
||||||
$ ./java/run_greetings_client.sh |
|
||||||
``` |
|
Loading…
Reference in new issue