从客户端干净地关闭GRPC-Java中的所有打开的流

Closing all open streams in GRPC-Java from client end cleanly

我正在使用GRPC-Java 1.1.2。 在一个活跃的GRPC会话中,我打开了一些双向流。 当客户端断开连接时,是否可以从客户端清除它们? 当我尝试断开连接时,我将以下查找运行了固定的次数,然后断开连接,但是我在服务器端看到以下错误(虽然不确定是否是由另一个问题引起的):

与客户端断开连接

1
2
3
4
while (!channel.awaitTermination(3, TimeUnit.SECONDS)) {
// check for upper bound and break if so
}
channel.shutdown().awaitTermination(3, TimeUnit.SECONDS);

服务器错误

1
2
E0414 11:26:48.787276000 140735121084416 ssl_transport_security.c:439] SSL_read returned 0 unexpectedly.
E0414 11:26:48.787345000 140735121084416 secure_endpoint.c:185]        Decryption error: TSI_INTERNAL_ERROR

如果要从客户端关闭gRPC(服务器端或bi-di)流,则必须将rpc调用附加到软件包io.grpc中的Context.CancellableContext

假设您有一个rpc:

1
2
3
service Messaging {
    rpc Listen (ListenRequest) returns (stream Message) {}
}

在客户端,您将像这样处理它:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
public class Messaging {
    private Context.CancellableContext mListenContext;

    private MessagingGrpc.MessagingStub getMessagingAsyncStub() {
    /* return your async stub */
    }

    public void listen(final ListenRequest listenRequest, final StreamObserver<Message> messageStream) {

        Runnable listenRunnable = new Runnable() {
            @Override
            public void run() {
                Messaging.this.getMessagingAsyncStub().listen(listenRequest, messageStream);
            }

        if (mListenContext != null && !mListenContext.isCancelled()) {
            Log.d(TAG,"listen: already listening");
            return;
        }

        mListenContext = Context.current().withCancellation();
        mListenContext.run(listenRunnable);
    }

    public void cancelListen() {
        if (mListenContext != null) {
            mListenContext.cancel(null);
            mListenContext = null;
        }
    }
}

调用cancelListen()将模拟错误'CANCELLED',连接将关闭,并且StreamObserver messageStreamonError会被抛出一条可抛出消息:'CANCELLED'。


如果使用shutdownNow(),它将更加主动地关闭您拥有的RPC流。 同样,您需要在调用awaitTermination()之前先调用shutdown()shutdownNow()

也就是说,更好的解决方案是在关闭通道之前正常结束所有RPC。