In this article, I decided to use gRPC for communication between the server and the client in the project I am currently working on, and I wrote that I did a lot of research while doing a tutorial to implement gRPC on Android. ..
What is gRPC? As mentioned in the overview, it is a communication protocol developed by Google. [Remote procedure call](https://ja.wikipedia.org/wiki/%E9%81%A0%E9%9A%94%E6%89%8B%E7%B6%9A%E3%81%8D%E5 % 91% BC% E5% 87% BA% E3% 81% 97) was developed to realize a technology that allows the server and client to communicate by directly calling the server method, and vice versa. I did.
In the conventional REST API, information was mainly exchanged with Json, but since the server and client implement separately, the implementation cost has increased.
However, gRPC can generate implementations of various programming languages just by defining API specifications in the .proto
file, which leads to a reduction in implementation cost on both the server and client.
In addition, Protocol Buffers enables faster communication than REST. [^ 1] [^ 2]
Hello World
First of all, while looking at the Official Quick Start Guide, I will try to move the application that returns Hello 〇 〇 (arbitrary input character string).
Download the sample code from the Github repository with git clone
.
$ # 2017/12/22 latest version 1.8.Download 0
$ git clone -b v1.8.0 https://github.com/grpc/grpc-java
$ #Move to the directory containing the sample code
$ cd grpc-java/examples
In the grpc-java / examples
directory, compile the server by doing the following:
$ ./gradlew installDist
Then let the server run.
$ ./build/install/examples/bin/hello-world-server
Connect your Android device in debug mode and execute the following with adb.
adb reverse tcp:8080 tcp:50051
Open a terminal different from the terminal on which the server was run, and compile and run the client.
$ cd android/helloworld
$ ./gradlew installDebug
If successful, the app will be installed on your device and you should see a screen like the one below.
Enter localhost
in Host, 8080
in Port (because it was reversed to 50051 with adb), enter the character you want to send appropriately in message (for example, world
), and the response is returned as follows. When it comes, communication with the server is successful!
It worked for the time being, but what's the actual content of the code?
Now let's look at the .proto
file, the server code, and the client (Android) code.
helloworld.proto
and generated code//Method definition
service Greeter {
rpc SayHello (HelloRequest) returns (HelloReply) {}
}
//Definition of request data structure
message HelloRequest {
string name = 1;
}
//Definition of response data structure
message HelloReply {
string message = 1;
}
In the helloworld.proto
file, write the API specification as described above.
Specifically, describe the method and the data structure of the data to be used.
For details on how to write, see Language Guide (proto3) in Protocol Buffers. See buffers / docs / proto3? hl = ja).
Compiling this helloworld.proto
file for each language will generate a language-specific gRPC interface.
Regarding the server side, it is written in the article I tried gRPC now, so I will omit it here.
helloworld.proto
The code generated from helloworld.proto
is built with gradlew
and placed in the following location in the ʻapp / build / generated` directory:
The code implemented as a sample looks like the following. (Partially omitted)
By the way, since OnClickListener is not implemented, I was searching around without knowing how to call the sendMessage method, but it seems that it is called from the layout xml.
HelloworldActivity.java
public class HelloworldActivity extends AppCompatActivity {
...
public void sendMessage(View view) {
new GrpcTask().execute();
}
private class GrpcTask extends AsyncTask<Void, Void, String> {
private String mHost;
private String mMessage;
private int mPort;
private ManagedChannel mChannel;
@Override
protected void onPreExecute() {
mHost = mHostEdit.getText().toString();
mMessage = mMessageEdit.getText().toString();
String portStr = mPortEdit.getText().toString();
mPort = TextUtils.isEmpty(portStr) ? 0 : Integer.valueOf(portStr);
mResultText.setText("");
}
@Override
protected String doInBackground(Void... nothing) {
try {
//Create Channel
mChannel = ManagedChannelBuilder.forAddress(mHost, mPort)
.usePlaintext(true)
.build();
//Create stub
GreeterGrpc.GreeterBlockingStub stub = GreeterGrpc.newBlockingStub(mChannel);
//Create request and specify value
HelloRequest message = HelloRequest.newBuilder().setName(mMessage).build();
//Execute sayHello method and receive reply
HelloReply reply = stub.sayHello(message);
return reply.getMessage();
} catch (Exception e) {
...
}
}
@Override
protected void onPostExecute(String result) {
try {
mChannel.shutdown().awaitTermination(1, TimeUnit.SECONDS);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
mResultText.setText(result);
}
}
}
Since communication needs to be implemented as asynchronous processing, we are creating a GrpcTask class that inherits AsyncTask.
Looking inside the doInBackground method that is doing asynchronous processing,
You can see that it is possible to realize the process of communicating and returning reply just by specifying request as an argument to the sayHello method in the same way as calling the method of the class. ..
When I first touched gRPC this time, I felt that it could be implemented much simpler than REST. I was very grateful to be able to intuitively write the communication part in the form of a method.
In the future, I would like to deepen my understanding while implementing it in the project.
Recommended Posts