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

因业务需要,需要使用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();
		}
	}

 

展开阅读全文
©️2020 CSDN 皮肤主题: 大白 设计师: CSDN官方博客 返回首页
实付0元
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值