整体配置和使用

个人理解,gRPC本质上是基于网络传输协议(主要是HTTP和HTTPS及更底层的tcp),序列化封装后,只暴露“函数名”和“函数入参”的网络请求。它的跨语言框架基本把网络传输的事情解决了,甚至接口定义和调用也通过脚本生成了(下文会提),基本上只需要把构建连接的channel新建出来就可以直接调用了。

定义接口

直接贴io.grpc的官方示例接口:

// Copyright 2015 The gRPC Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
syntax = "proto3";

// 是否将接口生成到多个文件、或生成到一个文件中
option java_multiple_files = true;
// 期望将生成代码放置到哪个Java包路径
option java_package = "io.grpc.examples.helloworld";
// 无需关心,改成自己的proto名即可
option java_outer_classname = "HelloWorldProto";
// 无需关心,可以不写
option objc_class_prefix = "HLW";

// 与服务端约定的调用“函数”的包路径,客户端不要修改,否则会报UNIMPLEMENTED: unknown service
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生成接口及数据模型

// 生成protobuf类
protoc.exe --java_out="D:/Temp" --proto_path="D:/Temp"  helloworld.proto
// 生成rpc调用类
protoc.exe --plugin=protoc-gen-grpc-java=D:/Temp/protoc-gen-grpc-java-1.65.1-windows-x86_64.exe --grpc-java_out="D:/Temp" --proto_path="D:/Temp"  helloworld.proto

对于Windows PowerShell,使用如下指令

# cd到目的目录
./protoc.exe --java_out="./" helloworld.proto
./protoc.exe --plugin=protoc-gen-grpc-java=./protoc-gen-grpc-java-1.65.1-windows-x86_64.exe --grpc-java_out="./"  helloworld.proto

Protocol Buffers下载地址:
https://github.com/protocolbuffers/protobuf/releases

protoc-gen-grpc-java可执行文件,下载地址:
https://search.maven.org/search?q=a:protoc-gen-grpc-java

gRPC Java代码生成,参考文档:
gRPC Java Codegen Plugin for Protobuf Compiler
https://github.com/grpc/grpc-java/tree/master/compiler

此处参考自:https://blog.csdn.net/netyeaxi/article/details/103824717

创建channel,stub即可调用

package com.example.tutorial;
 
import java.util.concurrent.ExecutionException;
import java.util.logging.Level;
import java.util.logging.Logger;
 
import com.example.tutorial.HelloWorld.HelloReply;
import com.example.tutorial.HelloWorld.HelloRequest;
import com.google.common.util.concurrent.ListenableFuture;
 
import io.grpc.ManagedChannel;
import io.grpc.ManagedChannelBuilder;
import io.grpc.StatusRuntimeException;
import io.grpc.stub.StreamObserver;
 
public class HelloWorldClients {
    private static final Logger logger = Logger.getLogger(HelloWorldClients.class.getName());
 
    private String host;
    private int port;
 
    public HelloWorldClients(String host, int port) {
        this.host = host;
        this.port = port;
    }
 
    public ManagedChannel getChannel() {
        return ManagedChannelBuilder.forAddress(host, port).usePlaintext().build();
    }
    public static void main(String[] args) throws Exception {
		HelloWorldClients client = new HelloWorldClients("localhost", 50051);
	 
		String user;
	 
		user = "world0";
		client.doSync(user);
	 
		user = "world1";
		client.doAsync(user);
	 
		user = "world2";
		client.doFuture(user);
    }
    
	//  a.同步调用
	public void doSync(String name) {
		GreeterGrpc.GreeterBlockingStub blockingStub = GreeterGrpc.newBlockingStub(getChannel());
	 
		logger.info("Will try to doSync");
		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());
	}
}

这里着重补充一下我遇到的问题一般去这里查:
https://grpc.github.io/grpc/core/md_doc_statuscodes.html

此外我还遇到了以下问题:

io.grpc.StatusRuntimeException: UNAVAILABLE: io exception
Channel Pipeline: [SslHandler#0, ProtocolNegotiators$ClientTlsHandler#0, WriteBufferingAndExceptionHandler#0, DefaultChannelPipeline$TailContext#0]

Caused by: javax.net.ssl.SSLHandshakeException: General OpenSslEngine problem

Caused by: java.security.cert.CertificateException: No subject alternative names matching IP address 10.253.62.32 found

后来发现是服务端配置了替代dns名,但客户端没有配置。增加如下代码即可

   channel = Grpc.newChannelBuilderForAddress(host, port, channelCredentials)	// channelCredentials是tls证书
           .overrideAuthority("dnsname") // 询问服务端的alt_names配置是什么,openssl.cnf文件中
           .build();
Logo

技术共进,成长同行——讯飞AI开发者社区

更多推荐