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

1 篇文章 0 订阅
1 篇文章 0 订阅

因业务需要,需要使用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();
		}
	}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值