Merge pull request #12 from LisaFC/master

grand unified hello world
pull/3109/head
LisaFC 10 years ago
commit 29ea501ce3
  1. 394
      README.md
  2. 41
      Step_0.md
  3. 32
      Step_1.md
  4. 85
      Step_2.md
  5. 83
      Step_3.md

@ -1,81 +1,393 @@
# gRPC Hello World Tutorial
# Getting started
## TODO: move this to the tutorial sub-folder
A great way to get introduced to gRPC is to work through this tutorial, which
walks you through the construction of a simple client and server and introduces
various features of gRPC.
Welcome to the developer documentation for gRPC, a language-neutral,
platform-neutral remote procedure call (RPC) system developed at Google.
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.
- Create a Java server that implements the schema interface.
- Create a Java client that accesses the server.
- Create a Go client that accesses the Java server.
- Update the service with advanced features like RPC streaming.
## What is gRPC?
## TODO: basic conceptual intro (anything more in-depth will go in gRPC Concepts doc)
# Get Started
<a name="hello"></a>
## Hello gRPC!
The rest of this page explains how you can set up your local machine for development.
If you just want to read the tutorial, you can go straight to the next step: [Step - 0](Step_0.md)
Now that you know a bit more about gRPC, the easiest way to see how it
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
your own computer. This way you can get hands-on practice of really writing
gRPC code.
This is an introductory example rather than a comprehensive tutorial, so
don't worry if you're not a Go or
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
management. You don't need to know anything about Git to follow the tutorial
other than how to install and run a few git commands.
<a name="setup"></a>
### Setup
# 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
installed you should have access to the git command line tool. The main
commands that you will need to use are:
- 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,
the example assumes that Java 8 is installed. See
[Install Java 8](http://docs.oracle.com/javase/8/docs/technotes/guides/install/install_overview.html)
for instructions.
Java gRPC is designed to work with both Java 7 and Java 8 - our example uses
Java 8. See
[Install Java
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
are server are structured as a standard [Maven](http://maven.apache.org/guides/getting-started/)
project. See [Install Maven](http://maven.apache.org/users/index.html) for instructions.
To simplify building and managing gRPC's dependencies, the Java client
and server are structured as a standard
[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
[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
generated code is checked into the Git repository. If you want to experiment
Having protoc installed isn't strictly necessary to follow along with this
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
[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…
Cancel
Save