0.編寫.protojava
syntax = "proto3"; option java_multiple_files = true; option java_package = "io.grpc.examples.helloworld"; option java_outer_classname = "HelloWorldProto"; option objc_class_prefix = "HLW"; package helloworld; service Greeter { rpc SayHello (HelloRequest) returns (HelloReply) {} } message HelloRequest { string name = 1; } message HelloReply { string message = 1; }
1.編譯.proto生成Java源文件:windows
protoc --grpc_out=..\\java --plugin=protoc-gen-grpc=D:\\Dev\\protoc\\protoc-gen-grpc-java-1.9.1-windows-x86_64.exe helloworld.proto protoc --java_out=..\\java helloworld.proto
2.生成CA根證書、服務器證書及客戶端證書bash
openssl genrsa -passout pass:111111 -des3 -out ca.key 4096 openssl req -passin pass:111111 -new -x509 -days 365 -key ca.key -out ca.crt -subj "/CN=localhost" openssl genrsa -passout pass:111111 -des3 -out server.key 4096 openssl req -passin pass:111111 -new -key server.key -out server.csr -subj "/CN=localhost" openssl x509 -req -passin pass:111111 -days 365 -in server.csr -CA ca.crt -CAkey ca.key -set_serial 01 -out server.crt openssl rsa -passin pass:111111 -in server.key -out server.key openssl genrsa -passout pass:111111 -des3 -out client.key 4096 openssl req -passin pass:111111 -new -key client.key -out client.csr -subj "/CN=localhost" openssl x509 -passin pass:111111 -req -days 365 -in client.csr -CA ca.crt -CAkey ca.key -set_serial 01 -out client.crt openssl rsa -passin pass:111111 -in client.key -out client.key openssl pkcs8 -topk8 -nocrypt -in client.key -out client.pem openssl pkcs8 -topk8 -nocrypt -in server.key -out server.pem
3.編寫Server端代碼服務器
package io.grpc.examples.helloworldtls; import io.grpc.Server; import io.grpc.examples.helloworld.GreeterGrpc; import io.grpc.examples.helloworld.HelloReply; import io.grpc.examples.helloworld.HelloRequest; import io.grpc.netty.GrpcSslContexts; import io.grpc.netty.NettyServerBuilder; import io.grpc.stub.StreamObserver; import io.netty.handler.ssl.ClientAuth; import io.netty.handler.ssl.SslContextBuilder; import io.netty.handler.ssl.SslProvider; import java.io.File; import java.io.IOException; import java.net.InetSocketAddress; import java.util.logging.Logger; public class HelloWorldServerTls { private static final Logger logger = Logger.getLogger(HelloWorldServerTls.class.getName()); private Server server; private final String host; private final int port; private final String certChainFilePath; private final String privateKeyFilePath; private final String trustCertCollectionFilePath; public HelloWorldServerTls(String host, int port, String certChainFilePath, String privateKeyFilePath, String trustCertCollectionFilePath) { this.host = host; this.port = port; this.certChainFilePath = certChainFilePath; this.privateKeyFilePath = privateKeyFilePath; this.trustCertCollectionFilePath = trustCertCollectionFilePath; } private SslContextBuilder getSslContextBuilder() { SslContextBuilder sslClientContextBuilder = SslContextBuilder.forServer(new File(certChainFilePath), new File(privateKeyFilePath)); if (trustCertCollectionFilePath != null) { sslClientContextBuilder.trustManager(new File(trustCertCollectionFilePath)); sslClientContextBuilder.clientAuth(ClientAuth.REQUIRE); } return GrpcSslContexts.configure(sslClientContextBuilder, SslProvider.OPENSSL); } private void start() throws IOException { server = NettyServerBuilder.forAddress(new InetSocketAddress(host, port)) .addService(new GreeterImpl()) .sslContext(getSslContextBuilder().build()) .build() .start(); logger.info("Server started, listening on " + port); Runtime.getRuntime().addShutdownHook(new Thread() { @Override public void run() { // Use stderr here since the logger may have been reset by its JVM shutdown hook. System.err.println("*** shutting down gRPC server since JVM is shutting down"); HelloWorldServerTls.this.stop(); System.err.println("*** server shut down"); } }); } private void stop() { if (server != null) { server.shutdown(); } } private void blockUntilShutdown() throws InterruptedException { if (server != null) { server.awaitTermination(); } } public static void main(String[] args) throws IOException, InterruptedException { if (args.length < 4 || args.length > 5) { System.out.println( "USAGE: HelloWorldServerTls host port certChainFilePath privateKeyFilePath " + "[trustCertCollectionFilePath]\n Note: You only need to supply trustCertCollectionFilePath if you want " + "to enable Mutual TLS."); System.exit(0); } final HelloWorldServerTls server = new HelloWorldServerTls(args[0], Integer.parseInt(args[1]), args[2], args[3], args.length == 5 ? args[4] : null); server.start(); server.blockUntilShutdown(); } static class GreeterImpl extends GreeterGrpc.GreeterImplBase { @Override public void sayHello(HelloRequest req, StreamObserver<HelloReply> responseObserver) { HelloReply reply = HelloReply.newBuilder().setMessage("Hello " + req.getName()).build(); responseObserver.onNext(reply); responseObserver.onCompleted(); } } }
4.編寫Client端代碼ide
package io.grpc.examples.helloworldtls; import io.grpc.ManagedChannel; import io.grpc.StatusRuntimeException; import io.grpc.examples.helloworld.GreeterGrpc; import io.grpc.examples.helloworld.HelloReply; import io.grpc.examples.helloworld.HelloRequest; import io.grpc.examples.helloworld.HelloWorldServer; import io.grpc.netty.GrpcSslContexts; import io.grpc.netty.NegotiationType; import io.grpc.netty.NettyChannelBuilder; import io.netty.handler.ssl.SslContext; import io.netty.handler.ssl.SslContextBuilder; import javax.net.ssl.SSLException; import java.io.File; import java.util.concurrent.TimeUnit; import java.util.logging.Level; import java.util.logging.Logger; public class HelloWorldClientTls { private static final Logger logger = Logger.getLogger(HelloWorldClientTls.class.getName()); private final ManagedChannel channel; private final GreeterGrpc.GreeterBlockingStub blockingStub; private static SslContext buildSslContext(String trustCertCollectionFilePath, String clientCertChainFilePath, String clientPrivateKeyFilePath) throws SSLException { SslContextBuilder builder = GrpcSslContexts.forClient(); if (trustCertCollectionFilePath != null) { builder.trustManager(new File(trustCertCollectionFilePath)); } if (clientCertChainFilePath != null && clientPrivateKeyFilePath != null) { builder.keyManager(new File(clientCertChainFilePath), new File(clientPrivateKeyFilePath)); } return builder.build(); } public HelloWorldClientTls(String host, int port, SslContext sslContext) throws SSLException { this(NettyChannelBuilder.forAddress(host, port) .negotiationType(NegotiationType.TLS) .sslContext(sslContext) .build()); } HelloWorldClientTls(ManagedChannel channel) { this.channel = channel; blockingStub = GreeterGrpc.newBlockingStub(channel); } public void shutdown() throws InterruptedException { channel.shutdown().awaitTermination(5, TimeUnit.SECONDS); } public void greet(String name) { logger.info("Will try to greet " + name + " ..."); HelloRequest request = HelloRequest.newBuilder().setName(name).build(); HelloReply response; try { response = blockingStub.sayHello(request); } catch (StatusRuntimeException e) { logger.log(Level.WARNING, "RPC failed: {0}", e.getStatus()); return; } logger.info("Greeting: " + response.getMessage()); } public static void main(String[] args) throws Exception { if (args.length < 2 || args.length == 4 || args.length > 5) { System.out.println("USAGE: HelloWorldClientTls host port [trustCertCollectionFilePath] " + "[clientCertChainFilePath] [clientPrivateKeyFilePath]\n Note: clientCertChainFilePath and " + "clientPrivateKeyFilePath are only needed if mutual auth is desired. And if you specify " + "clientCertChainFilePath you must also specify clientPrivateKeyFilePath"); System.exit(0); } { HelloWorldClientTls client; switch (args.length) { case 2: client = new HelloWorldClientTls(args[0], Integer.parseInt(args[1]), buildSslContext(null, null, null)); break; case 3: client = new HelloWorldClientTls(args[0], Integer.parseInt(args[1]), buildSslContext(args[2], null, null)); break; default: client = new HelloWorldClientTls(args[0], Integer.parseInt(args[1]), buildSslContext(args[2], args[3], args[4])); } try { String user = "world"; if (args.length > 0) { user = args[0]; /* Use the arg as the name to greet if provided */ } client.greet(user); } finally { client.shutdown(); } } } }
5.分別運行Server、Client代碼:ui
(Server端加入運行參數:localhost 50051 D:\openssl-keys\server.crt D:\openssl-keys\server.pem)this
(Client端加入運行參數:localhost 50051 D:\openssl-keys\ca.crt D:\openssl-keys\client.crt D:\openssl-keys\client.pem).net
運行以下:netty