Skip to content

Commit 72a977b

Browse files
authoredAug 8, 2024··
Dualstack example (#11451)
1 parent 40e2b16 commit 72a977b

File tree

12 files changed

+694
-31
lines changed

12 files changed

+694
-31
lines changed
 

‎examples/example-dualstack/README.md

+54
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
# gRPC Dualstack Example
2+
3+
The dualstack example uses a custom name resolver that provides both IPv4 and IPv6 localhost
4+
endpoints for each of 3 server instances. The client will first use the default name resolver and
5+
load balancers which will only connect tot he first server. It will then use the
6+
custom name resolver with round robin to connect to each of the servers in turn. The 3 instances
7+
of the server will bind respectively to: both IPv4 and IPv6, IPv4 only, and IPv6 only.
8+
9+
The example requires grpc-java to already be built. You are strongly encouraged
10+
to check out a git release tag, since there will already be a build of grpc
11+
available. Otherwise, you must follow [COMPILING](../../COMPILING.md).
12+
13+
### Build the example
14+
15+
To build the dualstack example server and client. From the
16+
`grpc-java/examples/example-dualstack` directory run:
17+
18+
```bash
19+
$ ../gradlew installDist
20+
```
21+
22+
This creates the scripts
23+
`build/install/example-dualstack/bin/dual-stack-server`
24+
and `build/install/example-dualstack/bin/dual-stack-client`.
25+
26+
To run the dualstack example, run the server with:
27+
28+
```bash
29+
$ ./build/install/example-dualstack/bin/dual-stack-server
30+
```
31+
32+
And in a different terminal window run the client.
33+
34+
```bash
35+
$ ./build/install/example-dualstack/bin/dual-stack-client
36+
```
37+
38+
### Maven
39+
40+
If you prefer to use Maven:
41+
42+
Run in the example-debug directory:
43+
44+
```bash
45+
$ mvn verify
46+
$ # Run the server in one terminal
47+
$ mvn exec:java -Dexec.mainClass=io.grpc.examples.dualstack.DualStackServer
48+
```
49+
50+
```bash
51+
$ # In another terminal run the client
52+
$ mvn exec:java -Dexec.mainClass=io.grpc.examples.dualstack.DualStackClient
53+
```
54+
+79
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
plugins {
2+
id 'application' // Provide convenience executables for trying out the examples.
3+
id 'java'
4+
5+
id "com.google.protobuf" version "0.9.4"
6+
7+
// Generate IntelliJ IDEA's .idea & .iml project files
8+
id 'idea'
9+
}
10+
11+
repositories {
12+
maven { // The google mirror is less flaky than mavenCentral()
13+
url "https://maven-central.storage-download.googleapis.com/maven2/" }
14+
mavenCentral()
15+
mavenLocal()
16+
}
17+
18+
java {
19+
sourceCompatibility = JavaVersion.VERSION_1_8
20+
targetCompatibility = JavaVersion.VERSION_1_8
21+
}
22+
23+
// IMPORTANT: You probably want the non-SNAPSHOT version of gRPC. Make sure you
24+
// are looking at a tagged version of the example and not "master"!
25+
26+
// Feel free to delete the comment at the next line. It is just for safely
27+
// updating the version in our release process.
28+
def grpcVersion = '1.67.0-SNAPSHOT' // CURRENT_GRPC_VERSION
29+
def protobufVersion = '3.25.3'
30+
31+
dependencies {
32+
implementation "io.grpc:grpc-protobuf:${grpcVersion}"
33+
implementation "io.grpc:grpc-netty:${grpcVersion}"
34+
implementation "io.grpc:grpc-stub:${grpcVersion}"
35+
implementation "io.grpc:grpc-services:${grpcVersion}"
36+
compileOnly "org.apache.tomcat:annotations-api:6.0.53"
37+
}
38+
39+
protobuf {
40+
protoc {
41+
artifact = "com.google.protobuf:protoc:${protobufVersion}"
42+
}
43+
plugins {
44+
grpc {
45+
artifact = "io.grpc:protoc-gen-grpc-java:${grpcVersion}"
46+
}
47+
}
48+
generateProtoTasks {
49+
all()*.plugins {
50+
grpc {}
51+
}
52+
}
53+
}
54+
55+
startScripts.enabled = false
56+
57+
task DualStackClient(type: CreateStartScripts) {
58+
mainClass = 'io.grpc.examples.dualstack.DualStackClient'
59+
applicationName = 'dual-stack-client'
60+
outputDir = new File(project.buildDir, 'tmp/scripts/' + name)
61+
classpath = startScripts.classpath
62+
}
63+
64+
task DualStackServer(type: CreateStartScripts) {
65+
mainClass = 'io.grpc.examples.dualstack.DualStackServer'
66+
applicationName = 'dual-stack-server'
67+
outputDir = new File(project.buildDir, 'tmp/scripts/' + name)
68+
classpath = startScripts.classpath
69+
}
70+
71+
application {
72+
applicationDistribution.into('bin') {
73+
from(DualStackClient)
74+
from(DualStackServer)
75+
filePermissions {
76+
unix(0755)
77+
}
78+
}
79+
}

‎examples/example-dualstack/pom.xml

+122
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
2+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
3+
<modelVersion>4.0.0</modelVersion>
4+
<groupId>io.grpc</groupId>
5+
<artifactId>example-dualstack</artifactId>
6+
<packaging>jar</packaging>
7+
<!-- Feel free to delete the comment at the end of these lines. It is just
8+
for safely updating the version in our release process. -->
9+
<version>1.67.0-SNAPSHOT</version><!-- CURRENT_GRPC_VERSION -->
10+
<name>example-dualstack</name>
11+
<url>https://github.com/grpc/grpc-java</url>
12+
13+
<properties>
14+
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
15+
<grpc.version>1.67.0-SNAPSHOT</grpc.version><!-- CURRENT_GRPC_VERSION -->
16+
<protoc.version>3.25.3</protoc.version>
17+
<!-- required for jdk9 -->
18+
<maven.compiler.source>1.8</maven.compiler.source>
19+
<maven.compiler.target>1.8</maven.compiler.target>
20+
</properties>
21+
22+
<dependencyManagement>
23+
<dependencies>
24+
<dependency>
25+
<groupId>io.grpc</groupId>
26+
<artifactId>grpc-bom</artifactId>
27+
<version>${grpc.version}</version>
28+
<type>pom</type>
29+
<scope>import</scope>
30+
</dependency>
31+
</dependencies>
32+
</dependencyManagement>
33+
34+
<dependencies>
35+
<dependency>
36+
<groupId>io.grpc</groupId>
37+
<artifactId>grpc-services</artifactId>
38+
</dependency>
39+
<dependency>
40+
<groupId>io.grpc</groupId>
41+
<artifactId>grpc-protobuf</artifactId>
42+
</dependency>
43+
<dependency>
44+
<groupId>io.grpc</groupId>
45+
<artifactId>grpc-stub</artifactId>
46+
</dependency>
47+
<dependency>
48+
<groupId>io.grpc</groupId>
49+
<artifactId>grpc-netty</artifactId>
50+
</dependency>
51+
<dependency>
52+
<groupId>org.apache.tomcat</groupId>
53+
<artifactId>annotations-api</artifactId>
54+
<version>6.0.53</version>
55+
<scope>provided</scope> <!-- not needed at runtime -->
56+
</dependency>
57+
<dependency>
58+
<groupId>io.grpc</groupId>
59+
<artifactId>grpc-netty-shaded</artifactId>
60+
<scope>runtime</scope>
61+
</dependency>
62+
<dependency>
63+
<groupId>junit</groupId>
64+
<artifactId>junit</artifactId>
65+
<version>4.13.2</version>
66+
<scope>test</scope>
67+
</dependency>
68+
<dependency>
69+
<groupId>io.grpc</groupId>
70+
<artifactId>grpc-testing</artifactId>
71+
<scope>test</scope>
72+
</dependency>
73+
</dependencies>
74+
75+
<build>
76+
<extensions>
77+
<extension>
78+
<groupId>kr.motd.maven</groupId>
79+
<artifactId>os-maven-plugin</artifactId>
80+
<version>1.7.1</version>
81+
</extension>
82+
</extensions>
83+
<plugins>
84+
<plugin>
85+
<groupId>org.xolstice.maven.plugins</groupId>
86+
<artifactId>protobuf-maven-plugin</artifactId>
87+
<version>0.6.1</version>
88+
<configuration>
89+
<protocArtifact>com.google.protobuf:protoc:${protoc.version}:exe:${os.detected.classifier}</protocArtifact>
90+
<pluginId>grpc-java</pluginId>
91+
<pluginArtifact>io.grpc:protoc-gen-grpc-java:${grpc.version}:exe:${os.detected.classifier}</pluginArtifact>
92+
</configuration>
93+
<executions>
94+
<execution>
95+
<goals>
96+
<goal>compile</goal>
97+
<goal>compile-custom</goal>
98+
</goals>
99+
</execution>
100+
</executions>
101+
</plugin>
102+
<plugin>
103+
<groupId>org.apache.maven.plugins</groupId>
104+
<artifactId>maven-enforcer-plugin</artifactId>
105+
<version>1.4.1</version>
106+
<executions>
107+
<execution>
108+
<id>enforce</id>
109+
<goals>
110+
<goal>enforce</goal>
111+
</goals>
112+
<configuration>
113+
<rules>
114+
<requireUpperBoundDeps/>
115+
</rules>
116+
</configuration>
117+
</execution>
118+
</executions>
119+
</plugin>
120+
</plugins>
121+
</build>
122+
</project>
+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
pluginManagement {
2+
repositories {
3+
maven { // The google mirror is less flaky than mavenCentral()
4+
url "https://maven-central.storage-download.googleapis.com/maven2/"
5+
}
6+
gradlePluginPortal()
7+
}
8+
}
9+
10+
rootProject.name = 'example-dualstack'
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
/*
2+
* Copyright 2024 The gRPC Authors
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package io.grpc.examples.dualstack;
18+
19+
import io.grpc.Channel;
20+
import io.grpc.ManagedChannel;
21+
import io.grpc.ManagedChannelBuilder;
22+
import io.grpc.NameResolverRegistry;
23+
import io.grpc.StatusRuntimeException;
24+
import io.grpc.examples.helloworld.GreeterGrpc;
25+
import io.grpc.examples.helloworld.HelloReply;
26+
import io.grpc.examples.helloworld.HelloRequest;
27+
import java.util.concurrent.TimeUnit;
28+
import java.util.logging.Level;
29+
import java.util.logging.Logger;
30+
31+
/**
32+
* A client that requests greetings from the {@link DualStackServer}.
33+
* First it sends 5 requests using the default nameresolver and load balancer.
34+
* Then it sends 10 requests using the example nameresolver and round robin load balancer. These
35+
* requests are evenly distributed among the 3 servers rather than favoring the server listening
36+
* on both addresses because the ExampleDualStackNameResolver groups the 3 servers as 3 endpoints
37+
* each with 2 addresses.
38+
*/
39+
public class DualStackClient {
40+
public static final String channelTarget = "example:///lb.example.grpc.io";
41+
private static final Logger logger = Logger.getLogger(DualStackClient.class.getName());
42+
private final GreeterGrpc.GreeterBlockingStub blockingStub;
43+
44+
public DualStackClient(Channel channel) {
45+
blockingStub = GreeterGrpc.newBlockingStub(channel);
46+
}
47+
48+
public static void main(String[] args) throws Exception {
49+
NameResolverRegistry.getDefaultRegistry()
50+
.register(new ExampleDualStackNameResolverProvider());
51+
52+
logger.info("\n **** Use default DNS resolver ****");
53+
ManagedChannel channel = ManagedChannelBuilder.forTarget("localhost:50051")
54+
.usePlaintext()
55+
.build();
56+
try {
57+
DualStackClient client = new DualStackClient(channel);
58+
for (int i = 0; i < 5; i++) {
59+
client.greet("request:" + i);
60+
}
61+
} finally {
62+
channel.shutdownNow().awaitTermination(5, TimeUnit.SECONDS);
63+
}
64+
65+
logger.info("\n **** Change to use example name resolver ****");
66+
/*
67+
Dial to "example:///resolver.example.grpc.io", use {@link ExampleNameResolver} to create connection
68+
"resolver.example.grpc.io" is converted to {@link java.net.URI.path}
69+
*/
70+
channel = ManagedChannelBuilder.forTarget(channelTarget)
71+
.defaultLoadBalancingPolicy("round_robin")
72+
.usePlaintext()
73+
.build();
74+
try {
75+
DualStackClient client = new DualStackClient(channel);
76+
for (int i = 0; i < 10; i++) {
77+
client.greet("request:" + i);
78+
}
79+
} finally {
80+
channel.shutdownNow().awaitTermination(5, TimeUnit.SECONDS);
81+
}
82+
}
83+
84+
public void greet(String name) {
85+
HelloRequest request = HelloRequest.newBuilder().setName(name).build();
86+
HelloReply response;
87+
try {
88+
response = blockingStub.sayHello(request);
89+
} catch (StatusRuntimeException e) {
90+
logger.log(Level.WARNING, "RPC failed: {0}", e.getStatus());
91+
return;
92+
}
93+
logger.info("Greeting: " + response.getMessage());
94+
}
95+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
/*
2+
* Copyright 2024 The gRPC Authors
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package io.grpc.examples.dualstack;
18+
19+
import io.grpc.Server;
20+
import io.grpc.ServerBuilder;
21+
import io.grpc.examples.helloworld.GreeterGrpc;
22+
import io.grpc.examples.helloworld.HelloReply;
23+
import io.grpc.examples.helloworld.HelloRequest;
24+
import io.grpc.netty.NettyServerBuilder;
25+
import io.grpc.stub.StreamObserver;
26+
import java.io.IOException;
27+
import java.net.InetSocketAddress;
28+
import java.util.ArrayList;
29+
import java.util.List;
30+
import java.util.concurrent.TimeUnit;
31+
import java.util.logging.Logger;
32+
33+
/**
34+
* Starts 3 different greeter services each on its own port, but all for localhost.
35+
* The first service listens on both IPv4 and IPv6,
36+
* the second on just IPv4, and the third on just IPv6.
37+
*/
38+
public class DualStackServer {
39+
private static final Logger logger = Logger.getLogger(DualStackServer.class.getName());
40+
private List<Server> servers;
41+
42+
public static void main(String[] args) throws IOException, InterruptedException {
43+
final DualStackServer server = new DualStackServer();
44+
server.start();
45+
server.blockUntilShutdown();
46+
}
47+
48+
private void start() throws IOException {
49+
InetSocketAddress inetSocketAddress;
50+
51+
servers = new ArrayList<>();
52+
int[] serverPorts = ExampleDualStackNameResolver.SERVER_PORTS;
53+
for (int i = 0; i < serverPorts.length; i++ ) {
54+
String addressType;
55+
int port = serverPorts[i];
56+
ServerBuilder<?> serverBuilder;
57+
switch (i) {
58+
case 0:
59+
serverBuilder = ServerBuilder.forPort(port); // bind to both IPv4 and IPv6
60+
addressType = "both IPv4 and IPv6";
61+
break;
62+
case 1:
63+
// bind to IPv4 only
64+
inetSocketAddress = new InetSocketAddress("127.0.0.1", port);
65+
serverBuilder = NettyServerBuilder.forAddress(inetSocketAddress);
66+
addressType = "IPv4 only";
67+
break;
68+
case 2:
69+
// bind to IPv6 only
70+
inetSocketAddress = new InetSocketAddress("::1", port);
71+
serverBuilder = NettyServerBuilder.forAddress(inetSocketAddress);
72+
addressType = "IPv6 only";
73+
break;
74+
default:
75+
throw new IllegalStateException("Unexpected value: " + i);
76+
}
77+
78+
servers.add(serverBuilder
79+
.addService(new GreeterImpl(port, addressType))
80+
.build()
81+
.start());
82+
logger.info("Server started, listening on " + port);
83+
}
84+
Runtime.getRuntime().addShutdownHook(new Thread(() -> {
85+
System.err.println("*** shutting down gRPC server since JVM is shutting down");
86+
try {
87+
DualStackServer.this.stop();
88+
} catch (InterruptedException e) {
89+
e.printStackTrace(System.err);
90+
}
91+
System.err.println("*** server shut down");
92+
}));
93+
}
94+
95+
private void stop() throws InterruptedException {
96+
for (Server server : servers) {
97+
server.shutdown().awaitTermination(30, TimeUnit.SECONDS);
98+
}
99+
}
100+
101+
private void blockUntilShutdown() throws InterruptedException {
102+
for (Server server : servers) {
103+
server.awaitTermination();
104+
}
105+
}
106+
107+
static class GreeterImpl extends GreeterGrpc.GreeterImplBase {
108+
109+
int port;
110+
String addressType;
111+
112+
public GreeterImpl(int port, String addressType) {
113+
this.port = port;
114+
this.addressType = addressType;
115+
}
116+
117+
@Override
118+
public void sayHello(HelloRequest req, StreamObserver<HelloReply> responseObserver) {
119+
String msg = String.format("Hello %s from server<%d> type: %s",
120+
req.getName(), this.port, addressType);
121+
HelloReply reply = HelloReply.newBuilder().setMessage(msg).build();
122+
responseObserver.onNext(reply);
123+
responseObserver.onCompleted();
124+
}
125+
}
126+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
/*
2+
* Copyright 2024 The gRPC Authors
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package io.grpc.examples.dualstack;
18+
19+
import com.google.common.collect.ImmutableMap;
20+
import io.grpc.EquivalentAddressGroup;
21+
import io.grpc.NameResolver;
22+
import io.grpc.Status;
23+
import java.net.InetSocketAddress;
24+
import java.net.SocketAddress;
25+
import java.net.URI;
26+
import java.util.ArrayList;
27+
import java.util.Arrays;
28+
import java.util.List;
29+
import java.util.stream.Collectors;
30+
31+
/**
32+
* A fake name resolver that resolves to a hard-coded list of 3 endpoints (EquivalentAddressGropu)
33+
* each with 2 addresses (one IPv4 and one IPv6).
34+
*/
35+
public class ExampleDualStackNameResolver extends NameResolver {
36+
static public final int[] SERVER_PORTS = {50051, 50052, 50053};
37+
38+
// This is a fake name resolver, so we just hard code the address here.
39+
private static final ImmutableMap<String, List<List<SocketAddress>>> addrStore =
40+
ImmutableMap.<String, List<List<SocketAddress>>>builder()
41+
.put("lb.example.grpc.io",
42+
Arrays.stream(SERVER_PORTS)
43+
.mapToObj(port -> getLocalAddrs(port))
44+
.collect(Collectors.toList())
45+
)
46+
.build();
47+
48+
private Listener2 listener;
49+
50+
private final URI uri;
51+
52+
public ExampleDualStackNameResolver(URI targetUri) {
53+
this.uri = targetUri;
54+
}
55+
56+
private static List<SocketAddress> getLocalAddrs(int port) {
57+
return Arrays.asList(
58+
new InetSocketAddress("127.0.0.1", port),
59+
new InetSocketAddress("::1", port));
60+
}
61+
62+
@Override
63+
public String getServiceAuthority() {
64+
return uri.getPath().substring(1);
65+
}
66+
67+
@Override
68+
public void shutdown() {
69+
}
70+
71+
@Override
72+
public void start(Listener2 listener) {
73+
this.listener = listener;
74+
this.resolve();
75+
}
76+
77+
@Override
78+
public void refresh() {
79+
this.resolve();
80+
}
81+
82+
private void resolve() {
83+
List<List<SocketAddress>> addresses = addrStore.get(uri.getPath().substring(1));
84+
try {
85+
List<EquivalentAddressGroup> eagList = new ArrayList<>();
86+
for (List<SocketAddress> endpoint : addresses) {
87+
// every server is an EquivalentAddressGroup, so they can be accessed randomly
88+
eagList.add(new EquivalentAddressGroup(endpoint));
89+
}
90+
91+
this.listener.onResult(ResolutionResult.newBuilder().setAddresses(eagList).build());
92+
} catch (Exception e){
93+
// when error occurs, notify listener
94+
this.listener.onError(Status.UNAVAILABLE.withDescription("Unable to resolve host ").withCause(e));
95+
}
96+
}
97+
98+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
/*
2+
* Copyright 2024 The gRPC Authors
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package io.grpc.examples.dualstack;
18+
19+
import io.grpc.NameResolver;
20+
import io.grpc.NameResolverProvider;
21+
22+
import java.net.URI;
23+
24+
public class ExampleDualStackNameResolverProvider extends NameResolverProvider {
25+
public static final String exampleScheme = "example";
26+
27+
@Override
28+
public NameResolver newNameResolver(URI targetUri, NameResolver.Args args) {
29+
return new ExampleDualStackNameResolver(targetUri);
30+
}
31+
32+
@Override
33+
protected boolean isAvailable() {
34+
return true;
35+
}
36+
37+
@Override
38+
protected int priority() {
39+
return 5;
40+
}
41+
42+
@Override
43+
// gRPC choose the first NameResolverProvider that supports the target URI scheme.
44+
public String getDefaultScheme() {
45+
return exampleScheme;
46+
}
47+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
// Copyright 2015 The gRPC Authors
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
syntax = "proto3";
15+
16+
option java_multiple_files = true;
17+
option java_package = "io.grpc.examples.helloworld";
18+
option java_outer_classname = "HelloWorldProto";
19+
option objc_class_prefix = "HLW";
20+
21+
package helloworld;
22+
23+
// The greeting service definition.
24+
service Greeter {
25+
// Sends a greeting
26+
rpc SayHello (HelloRequest) returns (HelloReply) {}
27+
}
28+
29+
// The request message containing the user's name.
30+
message HelloRequest {
31+
string name = 1;
32+
}
33+
34+
// The response message containing the greetings
35+
message HelloReply {
36+
string message = 1;
37+
}

‎examples/src/main/java/io/grpc/examples/loadbalance/ExampleNameResolver.java

+6-7
Original file line numberDiff line numberDiff line change
@@ -28,12 +28,12 @@
2828
import java.util.List;
2929
import java.util.Map;
3030
import java.util.stream.Collectors;
31-
import java.util.stream.Stream;
3231

3332
import static io.grpc.examples.loadbalance.LoadBalanceClient.exampleServiceName;
3433

3534
public class ExampleNameResolver extends NameResolver {
3635

36+
static private final int[] SERVER_PORTS = {50051, 50052, 50053};
3737
private Listener2 listener;
3838

3939
private final URI uri;
@@ -44,12 +44,11 @@ public ExampleNameResolver(URI targetUri) {
4444
this.uri = targetUri;
4545
// This is a fake name resolver, so we just hard code the address here.
4646
addrStore = ImmutableMap.<String,List<InetSocketAddress>>builder()
47-
.put(exampleServiceName,
48-
Stream.iterate(LoadBalanceServer.startPort,p->p+1)
49-
.limit(LoadBalanceServer.serverCount)
50-
.map(port->new InetSocketAddress("localhost",port))
51-
.collect(Collectors.toList())
52-
)
47+
.put(exampleServiceName,
48+
Arrays.stream(SERVER_PORTS)
49+
.mapToObj(port->new InetSocketAddress("localhost",port))
50+
.collect(Collectors.toList())
51+
)
5352
.build();
5453
}
5554

‎examples/src/main/java/io/grpc/examples/loadbalance/LoadBalanceServer.java

+15-17
Original file line numberDiff line numberDiff line change
@@ -24,23 +24,24 @@
2424
import io.grpc.stub.StreamObserver;
2525

2626
import java.io.IOException;
27+
import java.util.ArrayList;
28+
import java.util.List;
2729
import java.util.concurrent.TimeUnit;
2830
import java.util.logging.Logger;
2931

3032
public class LoadBalanceServer {
3133
private static final Logger logger = Logger.getLogger(LoadBalanceServer.class.getName());
32-
static public final int serverCount = 3;
33-
static public final int startPort = 50051;
34-
private Server[] servers;
34+
static final int[] SERVER_PORTS = {50051, 50052, 50053};
35+
private List<Server> servers;
3536

3637
private void start() throws IOException {
37-
servers = new Server[serverCount];
38-
for (int i = 0; i < serverCount; i++) {
39-
int port = startPort + i;
40-
servers[i] = ServerBuilder.forPort(port)
38+
servers = new ArrayList<>();
39+
for (int port : SERVER_PORTS) {
40+
servers.add(
41+
ServerBuilder.forPort(port)
4142
.addService(new GreeterImpl(port))
4243
.build()
43-
.start();
44+
.start());
4445
logger.info("Server started, listening on " + port);
4546
}
4647
Runtime.getRuntime().addShutdownHook(new Thread(() -> {
@@ -55,18 +56,14 @@ private void start() throws IOException {
5556
}
5657

5758
private void stop() throws InterruptedException {
58-
for (int i = 0; i < serverCount; i++) {
59-
if (servers[i] != null) {
60-
servers[i].shutdown().awaitTermination(30, TimeUnit.SECONDS);
61-
}
59+
for (Server server : servers) {
60+
server.shutdown().awaitTermination(30, TimeUnit.SECONDS);
6261
}
6362
}
6463

6564
private void blockUntilShutdown() throws InterruptedException {
66-
for (int i = 0; i < serverCount; i++) {
67-
if (servers[i] != null) {
68-
servers[i].awaitTermination();
69-
}
65+
for (Server server : servers) {
66+
server.awaitTermination();
7067
}
7168
}
7269

@@ -86,7 +83,8 @@ public GreeterImpl(int port) {
8683

8784
@Override
8885
public void sayHello(HelloRequest req, StreamObserver<HelloReply> responseObserver) {
89-
HelloReply reply = HelloReply.newBuilder().setMessage("Hello " + req.getName() + " from server<" + this.port + ">").build();
86+
HelloReply reply = HelloReply.newBuilder()
87+
.setMessage("Hello " + req.getName() + " from server<" + this.port + ">").build();
9088
responseObserver.onNext(reply);
9189
responseObserver.onCompleted();
9290
}

‎examples/src/main/java/io/grpc/examples/nameresolve/NameResolveClient.java

+5-7
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,7 @@
2626
import java.util.logging.Logger;
2727

2828
public class NameResolveClient {
29-
public static final String exampleScheme = "example";
30-
public static final String exampleServiceName = "lb.example.grpc.io";
29+
public static final String channelTarget = "example:///lb.example.grpc.io";
3130
private static final Logger logger = Logger.getLogger(NameResolveClient.class.getName());
3231
private final GreeterGrpc.GreeterBlockingStub blockingStub;
3332

@@ -56,11 +55,10 @@ public static void main(String[] args) throws Exception {
5655
Dial to "example:///resolver.example.grpc.io", use {@link ExampleNameResolver} to create connection
5756
"resolver.example.grpc.io" is converted to {@link java.net.URI.path}
5857
*/
59-
channel = ManagedChannelBuilder.forTarget(
60-
String.format("%s:///%s", exampleScheme, exampleServiceName))
61-
.defaultLoadBalancingPolicy("round_robin")
62-
.usePlaintext()
63-
.build();
58+
channel = ManagedChannelBuilder.forTarget(channelTarget)
59+
.defaultLoadBalancingPolicy("round_robin")
60+
.usePlaintext()
61+
.build();
6462
try {
6563
NameResolveClient client = new NameResolveClient(channel);
6664
for (int i = 0; i < 5; i++) {

0 commit comments

Comments
 (0)
Please sign in to comment.