Android客户端GRPC通信框架基本使用

xiaoxiao2025-11-07  5

因业务需要,需要使用rpc协议通信,java平台使用Google发布的GRPC框架应该是最合适的了。本篇主要讲解GPRC框架Android客户端的使用,关于RPC协议本篇不做说明,自行百度和Google;关于grpc框架高级应用和具体原理后面补上。RPC协议将通信数据映射成方法和接口调用。

本篇客户端使用android平台,服务器端为java控制台程序。废话不多说,直接上代码:

1.Android客户端

首先定义通信协议,grpc采用protobuf协议序列化,创建通信协议文件ReqAndRes.proto文件。具体协议规则请自行百度和Google。内容如下:

syntax="proto3"; option java_package = "com.dawson.grpc"; message ReqInfo{ string msg=1; } message ResInfo{ string msg=1; } service UserService{ rpc request(ReqInfo) returns(ResInfo){} rpc requestServerStream(ReqInfo) returns(stream ResInfo){} rpc requestClientStream(stream ReqInfo) returns(ResInfo){} rpc requestBothStream(stream ReqInfo) returns(stream ResInfo){} }

在src/main目录下面创建proto文件夹存放协议文件,然后使用protobuf插件将协议自动生成java文件。工程build.gradle配置的dependencies节点添加插件依赖:

classpath 'com.google.protobuf:protobuf-gradle-plugin:0.8.5'

module 下的build.gradle配置如下:

apply plugin: 'com.android.application' apply plugin: 'com.google.protobuf' android { compileSdkVersion 27 defaultConfig { applicationId "com.dawson.grpc" minSdkVersion 19 targetSdkVersion 27 versionCode 1 versionName "1.0" } buildTypes { release { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } } } protobuf { protoc { artifact = "com.google.protobuf:protoc:3.4.0" } plugins { javalite { artifact = "com.google.protobuf:protoc-gen-javalite:3.0.0" } grpc { artifact = 'io.grpc:protoc-gen-grpc-java:1.7.0' } } generateProtoTasks { all().each { task -> task.plugins { javalite {} grpc { // Options added to --grpc_out option 'lite' } } } } configurations.all { resolutionStrategy.force 'com.google.code.findbugs:jsr305:1.3.9' } } dependencies { implementation fileTree(dir: 'libs', include: ['*.jar']) implementation 'com.android.support:appcompat-v7:27.1.1' implementation 'com.android.support.constraint:constraint-layout:1.1.3' implementation 'io.grpc:grpc-okhttp:1.15.1' implementation 'io.grpc:grpc-protobuf-lite:1.15.1' implementation 'io.grpc:grpc-stub:1.15.1' implementation 'javax.annotation:javax.annotation-api:1.2' }

 然后build整个工程项目,会自动生成对应java文件。然后直接在页面调用,代码如下:

final ThreadPoolExecutor executor = new ThreadPoolExecutor(3, 5, 1, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>(10)); @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); findViewById(R.id.button1).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { request(); requestServerStream(); requestClientStream(); requestBothStream(); } }); init(); } Channel channel; private void init() { try { channel = ManagedChannelBuilder.forAddress("192.168.31.147", 6655) .usePlaintext() .build(); } catch (Exception ex) { showRes(ex.getMessage()); } } private void request() { executor.execute(new Runnable() { @Override public void run() { try { ReqAndRes.ReqInfo info = ReqAndRes.ReqInfo.newBuilder().setMsg("hello server").build(); UserServiceGrpc.UserServiceBlockingStub stub = UserServiceGrpc.newBlockingStub(channel); ReqAndRes.ResInfo res = stub.request(info); showRes(String.valueOf(res.getMsg())); } catch (Exception ex) { showRes(ex.getMessage()); } } }); } private void requestServerStream() { executor.execute(new Runnable() { @Override public void run() { try { ReqAndRes.ReqInfo info = ReqAndRes.ReqInfo.newBuilder().setMsg("hello server").build(); UserServiceGrpc.UserServiceBlockingStub stub = UserServiceGrpc.newBlockingStub(channel); Iterator<ReqAndRes.ResInfo> ress = stub.requestServerStream(info); while (ress.hasNext()) { showRes(String.valueOf(ress.next().getMsg())); } } catch (Exception ex) { showRes(ex.getMessage()); } } }); } private void requestClientStream() { executor.execute(new Runnable() { @Override public void run() { try { ReqAndRes.ReqInfo reqInfo1 = ReqAndRes.ReqInfo.newBuilder().setMsg("hello server 1").build(); ReqAndRes.ReqInfo reqInfo2 = ReqAndRes.ReqInfo.newBuilder().setMsg("hello server 2").build(); UserServiceGrpc.UserServiceStub stub = UserServiceGrpc.newStub(channel); StreamObserver<ReqAndRes.ResInfo> response = new StreamObserver<ReqAndRes.ResInfo>() { @Override public void onNext(ReqAndRes.ResInfo resInfo) { showRes(String.valueOf(resInfo.getMsg())); } @Override public void onError(Throwable t) { showRes(t.getMessage()); } @Override public void onCompleted() { showRes("onCompleted"); } }; StreamObserver<ReqAndRes.ReqInfo> request = stub.requestClientStream(response); request.onNext(reqInfo1); request.onNext(reqInfo2); request.onCompleted(); } catch (Exception ex) { showRes(ex.getMessage()); } } }); } private Thread bsThread; StreamObserver<ReqAndRes.ReqInfo> request; private void requestBothStream() { if (bsThread == null || request == null) { bsThread = new Thread() { @Override public void run() { try { UserServiceGrpc.UserServiceStub stub = UserServiceGrpc.newStub(channel); StreamObserver<ReqAndRes.ResInfo> response = new StreamObserver<ReqAndRes.ResInfo>() { @Override public void onNext(ReqAndRes.ResInfo res) { showRes(String.valueOf(res.getMsg())); } @Override public void onError(Throwable t) { showRes(t.getMessage()); } @Override public void onCompleted() { showRes("onCompleted"); } }; request = stub.requestBothStream(response); } catch (Exception ex) { showRes(ex.getMessage()); } } }; bsThread.start(); } if (bsThread == null || request == null) { return; } ReqAndRes.ReqInfo info = ReqAndRes.ReqInfo.newBuilder().setMsg("hello server" + System.currentTimeMillis() % 1000).build(); request.onNext(info); } private void showRes(final String msg) { Log.e("show_res", msg); }

rpc支持四种模式调用:普通阻塞,客户端流式rpc ,服务端流式rpc,双向流式rpc。分别对应以上代码的的四个方法。其中在创建channel时一定要调用.usePlaintext(),否则会自动加密导致服务端报错:无法找到http2头。

2.服务端代码

服务端创建java控制台程序,使用maven构建,同理需要使用插件将协议文件生成java文件。pom.xml文件gprc相关配置如下:

<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>com.dawson</groupId> <artifactId>maven_java_demo</artifactId> <version>0.0.1-SNAPSHOT</version> <packaging>jar</packaging> <name>maven_java_demo</name> <url>http://maven.apache.org</url> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <grpc.version>1.15.1</grpc.version> </properties> <dependencies> <dependency> <groupId>io.grpc</groupId> <artifactId>grpc-netty-shaded</artifactId> <version>1.15.1</version> </dependency> <dependency> <groupId>io.grpc</groupId> <artifactId>grpc-protobuf</artifactId> <version>1.15.1</version> </dependency> <dependency> <groupId>io.grpc</groupId> <artifactId>grpc-stub</artifactId> <version>1.15.1</version> </dependency> <dependency> <groupId>com.google.protobuf</groupId> <artifactId>protobuf-java</artifactId> <version>3.5.0</version> </dependency> <dependency> <groupId>io.grpc</groupId> <artifactId>grpc-core</artifactId> <version>${grpc.version}</version> </dependency> <dependency> <groupId>io.grpc</groupId> <artifactId>grpc-all</artifactId> <version>1.15.1</version> </dependency> <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-pool2</artifactId> <version>2.4.2</version> </dependency> </dependencies> <build> <finalName>com.ytf.rpc.demo</finalName> <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.1</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:1.15.1: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-compiler-plugin</artifactId> <version>2.3.2</version> <configuration> <source>1.8</source> <target>1.8</target> </configuration> </plugin> </plugins> </build> </project>

       在src/main/目录下面创建proto文件夹用于存放协议文件,然后使用maven构建,会自动生成Java文件,生成的Java文件在target/generated-source/protobuf/grpc-java和target/generated-source/protobuf/Java目录下面。然后在main/java目录中创建相同的package,再将生成的文件从target中拷贝到main/java对应包中。服务端需要实现服务UserServiceGrpc.UserServiceImplBase,代码如下:

package com.dawson.maven_java_demo; import com.dawson.grpc.UserServiceGrpc; import com.dawson.grpc.ReqAndRes; import com.dawson.grpc.ReqAndRes.ReqInfo; import com.dawson.grpc.ReqAndRes.ResInfo; import io.grpc.stub.StreamObserver; public class UserImpl extends UserServiceGrpc.UserServiceImplBase { @Override public void request(ReqInfo request, StreamObserver<ResInfo> responseObserver) { ReqAndRes.ResInfo res = ReqAndRes.ResInfo.newBuilder().setMsg("hello client").build(); responseObserver.onNext(res); responseObserver.onCompleted(); } @Override public void requestServerStream(ReqInfo request, StreamObserver<ResInfo> responseObserver) { ResInfo res1 = ResInfo.newBuilder().setMsg("hello client 1").build(); ResInfo res2 = ResInfo.newBuilder().setMsg("hello client 1").build(); responseObserver.onNext(res1); responseObserver.onNext(res2); responseObserver.onCompleted(); } @Override public StreamObserver<ReqInfo> requestClientStream(StreamObserver<ResInfo> responseObserver) { return new StreamObserver<ReqInfo>() { StringBuilder stringBuilder = new StringBuilder(); @Override public void onNext(ReqInfo res) { stringBuilder.append(res.getMsg()); stringBuilder.append(","); } @Override public void onError(Throwable t) { } @Override public void onCompleted() { ResInfo resInfo = ResInfo.newBuilder().setMsg("hello client (" + stringBuilder.toString() + ")") .build(); responseObserver.onNext(resInfo); responseObserver.onCompleted(); } }; } @Override public StreamObserver<ReqInfo> requestBothStream(StreamObserver<ResInfo> responseObserver) { Thread backThread = new Thread(new Runnable() { @Override public void run() { while (true) { try { Thread.sleep(3000); } catch (Exception e) { e.printStackTrace(); } ResInfo res = ResInfo.newBuilder().setMsg("hello client:" + System.currentTimeMillis() % 1000) .build(); responseObserver.onNext(res); } } }); backThread.start(); return new StreamObserver<ReqInfo>() { @Override public void onNext(ReqInfo value) { ResInfo.Builder res = ResInfo.newBuilder().setMsg("hello client (" + value.getMsg() + ")"); responseObserver.onNext(res.build()); } @Override public void onError(Throwable t) { } @Override public void onCompleted() { } }; } }

服务端启动grpc服务代码如下:

public static void main(String[] args) { System.out.println("Hello World!"); UserServiceGrpc.UserServiceImplBase userService = new UserImpl(); io.grpc.Server server = ServerBuilder.forPort(6655).addService(userService.bindService()).build(); try { server.start(); System.out.println("Server start success on port:6655"); server.awaitTermination(); } catch (Exception e) { e.printStackTrace(); } }

 

转载请注明原文地址: https://www.6miu.com/read-5039253.html

最新回复(0)