【问题标题】:Custom GRPC client stub - stream not started自定义 GRPC 客户端存根 - 流未启动
【发布时间】:2023-03-18 03:40:01
【问题描述】:

我正在尝试通过我的 Android 应用程序使用 TLS 访问自定义 GRPC 服务器(Anki Vector 机器人)。

我的 Android Studio 项目中有原始文件,并且所有必需的依赖项都可用。 Proto 文件生成 java 类,在我的活动中,我使用 OkHttpChannelBuilder 构建了一个通道。 然后我创建一个客户端存根(尝试使用异步和阻塞存根)

之后,我创建了一条请求消息并将其与存根一起发送。

代码编译良好,应用程序在我的手机上运行。 但是,发送请求时,我收到一条错误消息,指出流未启动。

在我能找到的所有示例中,我没有看到任何启动流的方法。

阻止流启动的问题可能是什么?

我收到的错误消息:

2019-02-10 01:08:59.303 14691-30895/com.test.anki.grpc D/vectorCTRL: Failed... : 
    java.lang.IllegalStateException: Not started
        at com.google.common.base.Preconditions.checkState(Preconditions.java:510)
        at io.grpc.internal.ClientCallImpl.request(ClientCallImpl.java:367)
        at io.grpc.PartialForwardingClientCall.request(PartialForwardingClientCall.java:34)
        at io.grpc.ForwardingClientCall.request(ForwardingClientCall.java:22)
        at io.grpc.ForwardingClientCall$SimpleForwardingClientCall.request(ForwardingClientCall.java:44)
        at io.grpc.PartialForwardingClientCall.request(PartialForwardingClientCall.java:34)
        at io.grpc.ForwardingClientCall.request(ForwardingClientCall.java:22)
        at io.grpc.ForwardingClientCall$SimpleForwardingClientCall.request(ForwardingClientCall.java:44)
        at io.grpc.PartialForwardingClientCall.request(PartialForwardingClientCall.java:34)
        at io.grpc.ForwardingClientCall.request(ForwardingClientCall.java:22)
        at io.grpc.stub.ClientCalls.startCall(ClientCalls.java:314)
        at io.grpc.stub.ClientCalls.asyncUnaryRequestCall(ClientCalls.java:280)
        at io.grpc.stub.ClientCalls.futureUnaryCall(ClientCalls.java:189)
        at io.grpc.stub.ClientCalls.blockingUnaryCall(ClientCalls.java:127)
        at Anki.Vector.external_interface.ExternalInterfaceGrpc$ExternalInterfaceBlockingStub.sayText(ExternalInterfaceGrpc.java:3554)
        at com.test.anki.grpc.MainActivity.testapi(MainActivity.java:1106)
        at com.test.anki.grpc.MainActivity$GrpcTask.doInBackground(MainActivity.java:1003)
        at com.test.anki.grpc.MainActivity$GrpcTask.doInBackground(MainActivity.java:996)
        at android.os.AsyncTask$2.call(AsyncTask.java:333)
        at java.util.concurrent.FutureTask.run(FutureTask.java:266)
        at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:245)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
        at java.lang.Thread.run(Thread.java:764)

我的代码是:

       ClientInterceptor clientInterceptor = new ClientInterceptor() {
            @Override
            public <ReqT, RespT> ClientCall<ReqT, RespT> interceptCall(MethodDescriptor<ReqT, RespT> methodDescriptor, CallOptions callOptions, Channel channel) {
                // Might need to try to inject the token using that?
                return new ClientInterceptors.CheckedForwardingClientCall<ReqT, RespT>(channel.newCall(methodDescriptor, callOptions)) {
                    @Override
                    protected void checkedStart(Listener listener, Metadata metadata) throws Exception {
                        Metadata.Key<String> key = Metadata.Key.of("authorization", Metadata.ASCII_STRING_MARSHALLER);
                        metadata.put(key, token);
                    }
                };
            }
        };

        SSLContext sslContext=null ;
        try {
            sslContext  = SSLContext.getInstance("TLS");
            sslContext .init(new KeyManager[0], new TrustManager[] {new DefaultTrustManager()}, new SecureRandom());
            SSLContext.setDefault(sslContext );
        } catch (NoSuchAlgorithmException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (KeyManagementException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        final SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();
        OkHttpClient okHttpClient = new OkHttpClient();
        okHttpClient.setSslSocketFactory(sslSocketFactory);
        okHttpClient.setHostnameVerifier(new HostnameVerifier() {
            @Override public boolean verify(String hostname, SSLSession session) {
                return true;
            }
        });

        Channel channel=null;
        try {
            //ManagedChannel channel = OkHttpChannelBuilder.forAddress(ipaddr, Integer.valueOf(port))
                    channel = OkHttpChannelBuilder.forAddress(ipaddr, Integer.valueOf(port))
                    //.overrideAuthority("Vector")
                    .sslSocketFactory(sslSocketFactory)
                    .intercept(clientInterceptor)
                    .build();

            //ExternalInterfaceGrpc.ExternalInterfaceStub externalInterfaceStub = ExternalInterfaceGrpc.newStub(channel);
            ExternalInterfaceGrpc.ExternalInterfaceBlockingStub externalInterfaceBlockingStub = ExternalInterfaceGrpc.newBlockingStub(channel);

            Messages.SayTextRequest sayTextRequest = Messages.SayTextRequest
                    .newBuilder()
                    .setText("Yolo")
                    .build();

            Messages.SayTextResponse res = externalInterfaceBlockingStub.sayText(sayTextRequest);
            Log.d(TAG, res.getStatus().toString());
} catch (Exception e) {
            StringWriter sw = new StringWriter();
            PrintWriter pw = new PrintWriter(sw);
            e.printStackTrace(pw);
            pw.flush();
            Log.d(TAG,String.format("Failed... : %n%s", sw));
        } finally {
            Log.d(TAG,"finally");
            /*
            try {
                 if(channel!=null) {((ManagedChannel) channel).shutdown().awaitTermination(1, TimeUnit.SECONDS);}
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
            */
        }

【问题讨论】:

    标签: android ssl grpc


    【解决方案1】:

    ClientCall 需要调用 start()。如果使用存根,则不需要调用start(),因为存根本身会调用start()。但是拦截器暴露给start()

    问题在于你的clientInterceptor

    protected void checkedStart(Listener listener, Metadata metadata) throws Exception {
        Metadata.Key<String> key = Metadata.Key.of("authorization", Metadata.ASCII_STRING_MARSHALLER);
        metadata.put(key, token);
        // FIXME: Missing call to delegate().start(listener, metadata);
    }
    

    名为 start() 的存根最终调用了您的拦截器的 checkedStart(),但随后拦截器并未在真正的 ClientCall 上调用 start。

    请注意,您不需要使用CheckedForwardingClientCall,因为您的checkedStart() 不会引发任何异常。 ForwardingClientCall 是更常用的类。 (覆盖 start() 而不是 checkedStart())。

    【讨论】:

    • 谢谢。所以你似乎有一个解决方案。但我不明白该怎么做才能修复。您建议将 CheckedForwardingClientCall 更改为 ForwardingClientCall 。但是,当我这样做时,我收到 ForwardingClientCall 的“无法解析符号”错误另外,您说拦截器没有在真正的 ClientCall 上调用 start。我该怎么做?
    • grpc.io/grpc-java/javadoc/io/grpc/ForwardingClientCall.html 。随意使用 SimpleForwardingClientCall。我指出了如何在 FIXME 中调用 start:delegate().start(listener, metadata);
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-07-18
    • 2021-11-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-02-27
    • 1970-01-01
    相关资源
    最近更新 更多