java-grpc demo

java-grpc

1. 导入依赖

<properties>
    <!-- grpc版本 -->
    <io.grpc.version>1.23.0</io.grpc.version>
</properties>

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>

<!-- grpc -->
<dependency>
    <groupId>io.grpc</groupId>
    <artifactId>grpc-protobuf</artifactId>
    <version>${io.grpc.version}</version>
</dependency>
<dependency>
    <groupId>io.grpc</groupId>
    <artifactId>grpc-stub</artifactId>
    <version>${io.grpc.version}</version>
</dependency>
<dependency>
    <groupId>io.grpc</groupId>
    <artifactId>grpc-core</artifactId>
    <version>${io.grpc.version}</version>
</dependency>
<!-- gRPC服务端依赖 -->
<dependency>
    <groupId>net.devh</groupId>
    <artifactId>grpc-server-spring-boot-starter</artifactId>
    <version>2.5.1.RELEASE</version>
</dependency>

2. protobuf编译插件

<plugin>
    <groupId>org.xolstice.maven.plugins</groupId>
    <artifactId>protobuf-maven-plugin</artifactId>
    <version>0.6.1</version>
    <extensions>true</extensions>
    <configuration>
        <protocArtifact>com.google.protobuf:protoc:3.8.0:exe:${os.detected.classifier}</protocArtifact>
        <pluginId>grpc-java</pluginId>
        <pluginArtifact>io.grpc:protoc-gen-grpc-java:${io.grpc.version}:exe:${os.detected.classifier}
        </pluginArtifact>
        <!--默认值-->
        <protoSourceRoot>${project.basedir}/src/main/proto</protoSourceRoot>
        <!--默认值-->
        <outputDirectory>${project.basedir}/src/main/java</outputDirectory>
        <!--设置是否在生成java文件之前清空outputDirectory的文件,默认值为true,设置为false时也会覆盖同名文件-->
        <clearOutputDirectory>false</clearOutputDirectory>
        <!--默认值-->
        <temporaryProtoFileDirectory>${project.build.directory}/protoc-dependencies
        </temporaryProtoFileDirectory>
        <!--更多配置信息可以查看https://www.xolstice.org/protobuf-maven-plugin/compile-mojo.html-->
    </configuration>
    <executions>
        <execution>
            <goals>
                <goal>compile</goal>
                <goal>compile-custom</goal>
            </goals>
        </execution>
    </executions>
</plugin>

3. proto协议定义

  • 注意:proto协议客户端与服务端必须一模一样,否则客户端是调不通服务端的。

(1)header.proto

syntax = "proto3";
package headerProto;

option java_multiple_files = true;
option java_package = "com.example.demo.proto3.header";

message Header{
	 uint32 nEnType=1;      	//内容数据是否使用了加密 0- 无加密1-AES加密 2-SM4加密
	 uint32 nErrCode=2;    		//错误码---如果是请求包,则该字段=0 如果是响应数据 则=对应的错误码
	 uint32 nPort=3;        	//服务端grpc端口  用来定位问题
	 string nIp=4;						//服务器ip
	 string strVersion=5;     //本条grpc通信协议版本“3.0.0”
	 string strFunName=6;   	//函数名称  请求时=请求者的函数名 响应时=服务端的函数名
	 string strUser=7;     		//进程名称  请求时=请求者的进程名称 响应时=服务端的进程名称--用来定位问题
	 string strTime=8;    		//时间戳 "2021-12-29 09:08:23:332"
	 string strKey=9;     		//加密的密钥
	 string strUuid=10;    		//每次请求的唯一ID 用于异步回调
}

(2)device.proto

syntax = "proto3";
package DV;

option java_multiple_files = true;
option java_package = "com.example.demo.proto3.device";

import "header.proto";

message MountRequest {
    headerProto.Header header = 1;
    uint32 optype = 2;  
    uint32  nDeviceType = 3;
    string strBoxIp = 4;	
    string authentication = 5;	
    string random= 6;			
    string platformip= 7;		
    int32 direction = 8;       
}

message MountResponse {
    headerProto.Header header = 1;
    int32 errorCode = 2;
    string errorMessage = 3;
    string deviceSn = 4; 
    string deviceType = 5; 
    string deviceModel = 6; 
    int32 deviceEnabledState = 7; 
    string mac = 8;
    string deviceName = 9;
    string softwareVersion = 10;
}

message queryDeviceSnRequest {
    headerProto.Header header = 1;
    uint32  nDeviceType = 2;
}

message queryDeviceSnResponse {
    headerProto.Header header = 1;
    string deviceSn = 2;
    int32 errorCode = 3;
    string errorMessage = 4;
}

message Response {
    headerProto.Header header = 1;
    int32 errorCode = 2;
    string errorMessage = 3;
}

message OpenDoorRequest {
    enum openDoorWay {
        singleOpenDoor = 0;
        longOpenDoor = 1;
        closeDoor = 2;
        longCloseDoor = 3;
    }
    headerProto.Header header = 1;
    openDoorWay openWay = 2; 
}

message RestartRequest {
    headerProto.Header header = 1;
}

message UpdatePwdIpNameRequest {
    enum updateType {
        password = 0;
        ip = 1;
        name = 2;
    }
    headerProto.Header header = 1;
    updateType type = 2;   
    string param = 3;
}

message HeartBeatRequest {
    headerProto.Header header = 1;
    string deviceSn = 2;       
    string deviceModel = 3;      
    string cpuUtilization = 4;    
    string gpuUtilization = 5;   
    string memory = 6;          
    string disk = 7;          
}

message SoftStateRequest {
    headerProto.Header header = 1;
    string deviceSn = 2;  
    string node = 3;       
    string softName = 4;    
    string status = 5;      
}

message DeviceAlarmRequest {
    headerProto.Header header = 1;
    string deviceSn = 2;      
    string alarmType = 3;       
    string alarmTime = 4;       
    string alarmDescription = 5;
    string alarmId = 6;       
}

message DeviceEnabledStateRequest {
    enum DeviceEnabledState {
        enable = 0;
        disable = 1;
    }
    headerProto.Header header = 1;
    DeviceEnabledState enabledState = 2;
}

message clearDeviceDatabaseRequest {
    headerProto.Header header = 1;
    string tempParam1 = 2;
    string tempParam2 = 3; 
}

message clearDeviceDatabaseResponse {
    headerProto.Header header = 1;
    int32 errorCode = 2; 
    string errorMessage = 3; 
}

service S
{
    rpc OpenDoor (OpenDoorRequest) returns (Response) {}

    rpc RestartDevice (RestartRequest) returns (Response) {}

    rpc DeviceMount (MountRequest) returns (MountResponse) {}

    rpc UpdatePwdIpName (UpdatePwdIpNameRequest) returns (Response) {}

    rpc updateEnabledStatus (DeviceEnabledStateRequest) returns (Response) {}

    rpc queryDeviceSn (queryDeviceSnRequest) returns (queryDeviceSnResponse) {}

    rpc clearDeviceDatabase (clearDeviceDatabaseRequest) returns (clearDeviceDatabaseResponse) {}

    rpc HeartBeat (HeartBeatRequest) returns (Response) {}

    rpc DeviceSoftState (SoftStateRequest) returns (Response) {}

    rpc DeviceAlarm (DeviceAlarmRequest) returns (Response) {}
}

4.客户端

@Component
public class DeviceGrpcClient {
    private SGrpc.SBlockingStub stub = null;

    private ManagedChannel channel = null;
    
    /**
     * 开门grpc接口
     */
    public DeviceResponse openDoor(String deviceIp, Integer throughWay) {
        DeviceResponse deviceResponse = new DeviceResponse();
        deviceResponse.setErrCode(500);
        deviceResponse.setMsg("开门失败");
        try {
            //初始化stub
            initStub(deviceIp, padPort);
            OpenDoorRequest.Builder builder = OpenDoorRequest.newBuilder();
            //配置请求头
            //Header header = GrpcUtil.setHeader(0, 0, 9090, "192.168.66.233", "3.3.0", "deviceMount", "strUser", "key", "uuid").build();
            //设置参数
            //builder.setHeader(header);
            builder.setOpenWayValue(throughWay);
            //调用grpc服务器
            Response response = stub.withDeadlineAfter(2, TimeUnit.SECONDS).openDoor(builder.build());
            if (response.getErrorCode() == 0) {
                deviceResponse.setErrCode(200);
                deviceResponse.setMsg("开门成功");
                return deviceResponse;
            }
        } catch (Exception e) {
            log.info("异常信息:{}", e.getMessage());
            deviceResponse.setMsg("连接设备失败,请确认设备信息和网络是否正确");
            return deviceResponse;
        } finally {
            channel.shutdownNow();
            log.info("is Shutdown: {}", channel.isShutdown());
        }
        return deviceResponse;
    }
    
    
    /**
     * 初始化stub
     */
    private void initStub(String ip, Integer port) {
        synchronized (this) {
            log.info("mount IP :{}", ip);
            channel = GrpcUtil.getChannel(ip, port);
            stub = SGrpc.newBlockingStub(channel);
        }
    }
    
}

5.服务端

@GrpcService
public class DeviceGrpcService extends SGrpc.SImplBase {
    
     @Override
    public void heartBeat(HeartBeatRequest request, StreamObserver<Response> responseObserver) {
        //获取header信息
        //返回状态码(0/1)和消息(***)
        String date = DateUtils.parseDateToStr("yyyy-MM-dd HH:mm:ss", new Date());
        Header.Builder builder = Header.newBuilder().setStrTime(date);
        Response response = Response.newBuilder().setHeader(builder.build()).setErrorCode(0).setErrorMessage("心跳接收成功").build();
        // onNext()方法向客户端返回结果
        responseObserver.onNext(response);
        // 告诉客户端这次调用已经完成
        responseObserver.onCompleted();
        HeartInfo heartInfo = new HeartInfo(request.getDeviceSn(), request.getDeviceModel(), request.getMemory(), request.getDisk(), request.getCpuUtilization(), request.getGpuUtilization());
        R receiveHeart = remoteDeviceService.receiveHeart(heartInfo, SecurityConstants.INNER);
    }
    
}

6.参数配置

grpc:
  server:
    port: 9091
    #服务端配置心跳,向客户端发送心跳
    #enable-keep-alive: true
    #发送心跳时间间隔
    #keep-alive-time: 60
    #收到心跳回复超时时间
    #keep-alive-timeout: 20
    #允许客户端配置的活跃时间,默认5min,单位s,如果配置的活跃时间大于允许时间,将会关闭连接
    permit-keep-alive-time: 300
    #允许客户端向服务端发心跳,默认为false
    permit-keep-alive-without-calls: true
    max-inbound-message-size: 1048576000



#rpc server 参数配置:
enableKeepAlive #服务端是否开启心跳;默认为false ,
keepAliveTime #服务端每隔多少时间向客户端发送心跳检测;默认60s  单位秒  
keepAliveTimeout #服务端发送心跳收到回复的超时时间;默认20s  单位秒 
permitKeepAliveTime #指定允许客户端配置的最积极的保持活动时间 默认5min 单位秒
permitKeepAliveWithoutCalls #是否允许客户端发送保持活动的HTTP/2 PING 默认false
healthServiceEnabled #是否开启服务健康检查 默认true
maxInboundMessageSize #接收文件大小 单位byte 默认为4MB
port #grpc-server端口 默认9090


#在这里还需要特别注意一个问题, grpc client 的keepalive 的 时间设定 需要在server 允许范围内,否则,server 会认为你是捣蛋的,给你发送一个GOAWAY 消息,把和client 的连接强制关掉
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
下面是一个简单的 Android gRPC Java 传输文件的演示,其中包括客户端和服务器端的代码。 1. 客户端代码 ```java public class FileTransferClient { private ManagedChannel channel; private FileTransferServiceGrpc.FileTransferServiceBlockingStub blockingStub; public FileTransferClient(String host, int port) { channel = ManagedChannelBuilder.forAddress(host, port) .usePlaintext() .build(); blockingStub = FileTransferServiceGrpc.newBlockingStub(channel); } public void shutdown() throws InterruptedException { channel.shutdown().awaitTermination(5, TimeUnit.SECONDS); } public void uploadFile(File file) { try { FileInputStream inputStream = new FileInputStream(file); StreamObserver<FileChunk> responseObserver = blockingStub.uploadFile(new StreamObserver<UploadStatus>() { @Override public void onNext(UploadStatus value) { Log.d("FileUpload", "Upload status: " + value.getStatus()); } @Override public void onError(Throwable t) { Log.e("FileUpload", "Upload error: " + t.getMessage()); } @Override public void onCompleted() { Log.d("FileUpload", "Upload completed"); } }); byte[] buffer = new byte[1024]; int bytesRead; while ((bytesRead = inputStream.read(buffer)) != -1) { FileChunk fileChunk = FileChunk.newBuilder() .setData(ByteString.copyFrom(buffer, 0, bytesRead)) .build(); responseObserver.onNext(fileChunk); } responseObserver.onCompleted(); inputStream.close(); } catch (IOException e) { e.printStackTrace(); } } } ``` 2. 服务器端代码 ```java public class FileTransferServer { private static final Logger logger = Logger.getLogger(FileTransferServer.class.getName()); private Server server; public void start(int port) throws IOException { server = ServerBuilder.forPort(port) .addService(new FileTransferServiceImpl()) .build() .start(); logger.info("Server started, listening on " + port); Runtime.getRuntime().addShutdownHook(new Thread() { @Override public void run() { System.err.println("*** Shutting down gRPC server since JVM is shutting down"); FileTransferServer.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 { final FileTransferServer server = new FileTransferServer(); server.start(50051); server.blockUntilShutdown(); } static class FileTransferServiceImpl extends FileTransferServiceGrpc.FileTransferServiceImplBase { private FileOutputStream outputStream; @Override public StreamObserver<FileChunk> uploadFile(StreamObserver<UploadStatus> responseObserver) { outputStream = null; try { outputStream = new FileOutputStream("path_to_save_file"); // 修改为你想要保存文件的路径 } catch (FileNotFoundException e) { e.printStackTrace(); } return new StreamObserver<FileChunk>() { @Override public void onNext(FileChunk value) { try { outputStream.write(value.getData().toByteArray()); } catch (IOException e) { e.printStackTrace(); } } @Override public void onError(Throwable t) { t.printStackTrace(); } @Override public void onCompleted() { try { outputStream.flush(); outputStream.close(); UploadStatus uploadStatus = UploadStatus.newBuilder() .setStatus("Success") .build(); responseObserver.onNext(uploadStatus); responseObserver.onCompleted(); } catch (IOException e) { e.printStackTrace(); } } }; } } } ``` 这个示例演示了如何使用 gRPC 在 Android 上上传文件。在客户端代码中,我们创建了一个 `FileTransferClient` 类,它包含了与服务器通信的代码。在服务器端代码中,我们创建了一个 `FileTransferServer` 类,它包含了接收上传文件的代码。文件被分成块,并逐个发送到服务器。在服务器端,每个块被写入文件,直到接收到所有的块。在客户端,我们会收到上传的状态,包括上传是否成功以及错误信息。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值