Java客户端对接go后端gRPC踩坑记录-包括UNIMPLEMENTED、SAN报错等
/////// 是否将接口生成到多个文件、或生成到一个文件中// 期望将生成代码放置到哪个Java包路径// 无需关心,改成自己的proto名即可// 无需关心,可以不写// 与服务端约定的调用“函数”的包路径,客户端不要修改,否则会报UNIMPLEMENTED: unknown service// “函数”结构的接口// 以下为请求体和返回值的数据结构。
Java使用gRPC踩坑记录
整体配置和使用
个人理解,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();
更多推荐
所有评论(0)