This exercise is intended to demonstrate the functionality and implementation of Remote Procedure Call (RPC) technology using the Open Source High Performance gRPC Framework gRPC Frameworks (https://grpc.io). It shows that this framework can be used to develop a middleware system for connecting several services developed with different programming languages.
Document all individual implementation steps and any problems that arise in a log (Markdown). Create a GITHUB repository for this project and add the link to it in the comments.
gRPC is a cross-platform RPC framework using Protocol Buffers for serialization, supporting multiple languages for interoperability.
- Client sends request.
- Server processes and responds.
- Client receives response.
- Define schema in
.proto
file. - Generate code for target language.
- Serialize/deserialize data for communication.
- Compact and efficient.
- Cross-language compatibility.
- Backward compatibility.
- Small/simple data.
- Text-human readability needed.
- No cross-platform requirement.
int32
(integer).string
(text).bool
(boolean).
I followed the tutorial until I encountered the following error: The java class HelloWorldClient that I copied from the task did not find the package HelloWorldService. What was particularly strange was that it could find some methods and not others. After I couldn't find a possible solution, I found a solution with the help of Pavle, the person sitting next to me. If you add this line to the proto file
option java_package = "org.example";
This sets the location of the Libery that creates the proto file. Normally this is used to make the programme clearer so that the Libery does not end up in a strange place. In this case it is used to have a safe location for the classes to find it.
An unexpected error occurred after executing from the server and then from the client
This is caused by a network crash of the client. One possible reason would be because the client is not shut down properly.
Solution approach:
channel.shutdown()
-----------------
channel.shutdown().awaitTermination(5, TimeUnit.SECONDS);
In the client, channel.shutdown()
is called to close the gRPC channel. However, it is recommended to use channel.shutdown().awaitTermination(5, TimeUnit.SECONDS)
instead, so that the channel is shut down correctly and all resources are released properly.
Another prevention measure is a try-catch loop in the server
server.awaitTermination();
----------------------
try {
server.awaitTermination();
} catch (InterruptedException e) {
System.err.println("Server interrupted: " + e.getMessage());
}
It makes sense to improve the error handling in the server for such scenarios. gRPC provides standard logs, but additional specific exception handling mechanisms could help to minimise the error.
https://intuting.medium.com/implement-grpc-service-using-java-gradle-7a54258b60b8
ManagedChannel channel = ManagedChannelBuilder.forAddress("localhost", 50051)
.usePlaintext()
.build();
ManagedChannel
: Represents the communication channel between the client and the server.ManagedChannelBuilder.forAddress(‘localhost’, 50051)
: Builds a channel that connects to a server onlocalhost
(the local host) and port50051
..usePlaintext()
: Specifies that the channel does not use encryption (TLS). This is often common in test or development environments..build()
: Builds the channel.
HelloWorldServiceGrpc.HelloWorldServiceBlockingStub stub = HelloWorldServiceGrpc.newBlockingStub(channel);
- HelloWorldServiceGrpc.HelloWorldServiceBlockingStub`:** A stub is a client-side proxy object that forwards method calls to the server.
- A blocking stub is used here, i.e. the method calls block the calling thread until the server responds.
.newBlockingStub(channel)
: Creates a stub that is connected to the previously created channel.
Hello.HelloResponse helloResponse = stub.hello(Hello.HelloRequest.newBuilder()
.setFirstname("Max")
.setLastname("Mustermann")
.build());
-
Hello.HelloRequest.newBuilder()
: Creates a newHelloRequest
(based on the protobuf definition)..setFirstname(‘Max’)
: Sets the first name in the request..setLastname(‘Mustermann’)
: Sets the last name in the request..build()
: Completes the request object.
-
stub.hello(...)
: Executes thehello
method of the gRPC service on the server. The request is sent to the server and the response (HelloResponse
) is returned. -
HelloResponse helloResponse`:** Saves the response from the server.
public void start() throws IOException { server = ServerBuilder.forPort(PORT) .addService(new HelloWorldServiceImpl()) .build() .start();
} ```
-
server = ServerBuilder.forPort(PORT)
: Creates a server that listens on the specified port (50051
). -
.addService(new HelloWorldServiceImpl())
: Registers the gRPC service that is to process requests.HelloWorldServiceImpl
: An implementation of the gRPC service (based on the protobuf definition). This class processes the incoming requests.
-
.build()
: Builds the server with the specified settings. -
.start()
: Starts the server and makes it ready to receive requests. -
throws IOException
: If an error occurs when starting the server (e.g. port already occupied).public void blockUntilShutdown() throws InterruptedException { if (server == null) { return; } try { server.awaitTermination(); } catch (InterruptedException e) { System.err.println("Server interrupted: " + e.getMessage()); }
} ```
server.awaitTermination()
: Wartet darauf, dass der Server beendet wird.- Diese Methode blockiert, bis der Server entweder durch einen Systembefehl oder durch eine Ausnahme gestoppt wird.
- Abbruchbehandlung (
catch
-Block): Gibt eine Fehlermeldung aus, falls der Server durch eine Unterbrechung beendet wird.
@Override
public void hello(Hello.HelloRequest request, StreamObserver<Hello.HelloResponse> responseObserver) {
-
@Override
: Indicates that the method from the base class will be overridden. -
hello(...)
: The implementation of thehello
method as defined in the protobuf definition in the portofilerpc hello(HelloRequest) returns (HelloResponse) {}
-
Parameter:
- HelloRequest request
:** The request object that is sent by the client. It contains fields such as
firstnameand
lastname`. StreamObserver<Hello.HelloResponse> responseObserver
: An observer with which the server sends the response back to the client.
- HelloRequest request
added VoteData Class with VoteService Class and this methode to return the String
public String getVoteDataAsJSON( String regionID) {
VoteData data = VoteService.getVoteData(regionID);
return data.toJSON();
}
Made a new Server Class and a new proto file and a new Client and a new Service, which follow the same exact way then explained above,