由于新工作中要使用grpc框架,之前也接触过一些,但是没有静下心来学它,加之网上对于这个方面的资料确实比较少,而且没有书,所以记录下来加深一下印象。
我主要参考的资料如下,当然也可以参考中文版的,但是感觉英文的还是更原汁原味吧。
至于什么是grpc?它有什么特点之类的问题就不介绍了,官网及csdn的博客里有很多赘述。这里只记录一下如何上手做的一个简单的grpc服务实例,因为我发现官网的描述并不太直观,尤其是生成服务端很客户端代码部分有一些模糊。
准备工作
准备好一个.proto的文件,这是定义rpc服务的关键文件,就以官网例子中的helloworld.proto为例。
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; // The greeting service definition. service Greeter { // Sends a greeting rpc SayHello (HelloRequest) returns (HelloReply) {} } // The request message containing the user's name. message HelloRequest { string name = 1; } // The response message containing the greetings message HelloReply { string message = 1; }
生成代码
有了.proto文件,有多种方式可以生成服务端和客户端的代码,这里采用protoc在maven中的插件生成的,pom.xml配置如下:
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>grpc-generate-test</groupId> <artifactId>grpc-generate-test</artifactId> <version>1.0-SNAPSHOT</version> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <grpc.version>1.11.0</grpc.version><!-- CURRENT_GRPC_VERSION --> <netty.tcnative.version>2.0.7.Final</netty.tcnative.version> </properties> <dependencies> <dependency> <groupId>io.grpc</groupId> <artifactId>grpc-netty</artifactId> <version>${grpc.version}</version> </dependency> <dependency> <groupId>io.grpc</groupId> <artifactId>grpc-protobuf</artifactId> <version>${grpc.version}</version> </dependency> <dependency> <groupId>io.grpc</groupId> <artifactId>grpc-stub</artifactId> <version>${grpc.version}</version> </dependency> </dependencies> <build> <extensions> <extension> <groupId>kr.motd.maven</groupId> <artifactId>os-maven-plugin</artifactId> <version>1.5.0.Final</version> </extension> </extensions> <plugins> <plugin> <groupId>org.xolstice.maven.plugins</groupId> <artifactId>protobuf-maven-plugin</artifactId> <version>0.5.0</version> <configuration> <protocArtifact>com.google.protobuf:protoc:3.5.1-1:exe:${os.detected.classifier}</protocArtifact> <pluginId>grpc-java</pluginId> <pluginArtifact>io.grpc:protoc-gen-grpc-java:${grpc.version}:exe:${os.detected.classifier}</pluginArtifact> </configuration> <executions> <execution> <goals> <goal>compile</goal> <goal>compile-custom</goal> </goals> </execution> </executions> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-enforcer-plugin</artifactId> <version>1.4.1</version> <executions> <execution> <id>enforce</id> <goals> <goal>enforce</goal> </goals> <configuration> <rules> <requireUpperBoundDeps/> </rules> </configuration> </execution> </executions> </plugin> </plugins> </build> </project>
之后在命令行中输入命令:
mvn compile
如果成功则能在target目录找到对应生成好的代码文件:
实现服务端和客户端代码
新建一个maven工程,将上面生成好的代码文件拷贝进去,新建一个GreeterService.java实现服务端的逻辑:
public class GreeterService extends GreeterGrpc.GreeterImplBase { @Override public void sayHello(HelloRequest req, StreamObserver<HelloReply> responseObserver) { HelloReply reply = HelloReply.newBuilder().setMessage("Hello2 " + req.getName()).build(); responseObserver.onNext(reply); responseObserver.onCompleted(); } }
新建一个HelloWorldServer.java实现绑定端口号,注册服务的实现类等工作:
public class HelloWorldServer { private static final Logger logger = Logger.getLogger(HelloWorldServer.class.getName()); private Server server; private void start() throws IOException { /* The port on which the server should run */ int port = 50051; server = ServerBuilder.forPort(port) .addService(new GreeterService()) .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"); HelloWorldServer.this.stop(); System.err.println("*** server shut down"); } }); } private void stop() { if (server != null) { server.shutdown(); } } /** * Await termination on the main thread since the grpc library uses daemon threads. */ private void blockUntilShutdown() throws InterruptedException { if (server != null) { server.awaitTermination(); } } /** * Main launches the server from the command line. */ public static void main(String[] args) throws IOException, InterruptedException { final HelloWorldServer server = new HelloWorldServer(); server.start(); server.blockUntilShutdown(); } }
新建一个HelloWorldClient.java调用服务端的服务获得结果:
public class HelloWorldClient { private static final Logger logger = Logger.getLogger(HelloWorldClient.class.getName()); private final ManagedChannel channel; private final GreeterGrpc.GreeterBlockingStub blockingStub; /** Construct client connecting to HelloWorld server at {@code host:port}. */ public HelloWorldClient(String host, int port) { this(ManagedChannelBuilder.forAddress(host, port) // Channels are secure by default (via SSL/TLS). For the example we disable TLS to avoid // needing certificates. .usePlaintext(true) .build()); } /** Construct client for accessing RouteGuide server using the existing channel. */ HelloWorldClient(ManagedChannel channel) { this.channel = channel; blockingStub = GreeterGrpc.newBlockingStub(channel); } public void shutdown() throws InterruptedException { channel.shutdown().awaitTermination(5, TimeUnit.SECONDS); } /** Say hello to server. */ 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()); } /** * Greet server. If provided, the first element of {@code args} is the name to use in the * greeting. */ public static void main(String[] args) throws Exception { HelloWorldClient client = new HelloWorldClient("localhost", 50051); try { /* Access a service running on the local machine on port 50051 */ 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(); } } }
先运行服务端的代码,再执行客户端的代码,得到结果如下:
五月 06, 2018 5:10:49 下午 HelloWorldClient greet
信息: Will try to greet world ...
五月 06, 2018 5:10:50 下午 HelloWorldClient greet
信息: Greeting: Hello2 world
至此完成了简单的从生成代码到实现具体服务功能的过程,之后如果有新的学习内容再继续总结。以下是博客里提到的工程文件,仅供参考
欢迎关注我的个人的博客www.zhijianliu.cn, 虚心求教,有错误还请指正轻拍,谢谢
版权声明:本文出自志健的原创文章,未经博主允许不得转载