摘要:如果客户端通道处于READY
状态并且网络断开连接,则该通道将变得不可用,并且一旦重新建立网络连接,客户端将不会尝试重新连接到服务器。 。发生READY
错误(由我的客户端应用程序设置的最后期限)后,通道不会从TRANSIENT_FAILURE
状态转换为DEADLINE_EXCEEDED
。
您使用的是什么版本的gRPC和使用什么语言?
1.17.2 在1.11.x版中有相同的发行经验 C ++
什么操作系统(Linux,Windows等)和版本?
在Ubuntu 16.04上运行的客户端。 运行Windows Enterprise的服务器。
您做了什么?
服务器和客户端都在连接的网络上启动。我可以成功拨打电话并从服务器接收响应。当网络关闭时,服务器会收到"Disconnected client - Endpoint read failed"
错误。此调试消息中的其他一些相关字段-"grpc_status":14 (UNAVAILABLE), "occured_during_write":0, "description":"An established connection was aborted by the software in your host machine"
。
在断开网络连接时,客户端根本不会打印出任何日志(使用GRPC_TRACE=connectivity_state,call_error,op_failure,server_channel,client_channel,channel GRPC_VERBOSITY=DEBUG
)。
再次打开网络后,服务器和客户端上都不会遇到日志。尝试使用客户端进行呼叫(发送启动请求)会导致重复的DEADLINE_EXCEEDED
错误。此时关闭网络连接不会导致服务器端"Disconnected client"
错误。
客户端上下文设置为使用截止日期(经过2秒和10秒测试)。在这种情况下,将使用同步调用。
代码段:
/rpc_service.proto
syntax = "proto3";
import "google/rpc/status.proto";
message RpcRequest {
}
message RpcResponse {
}
service RpcService{
rpc Call(RpcRequest) returns (RpcResponse);
}
/client.cc
初始化:
std::unique_ptrRpcService::Stub stub_ = RpcService::NewStub(::grpc::CreateChannel(
server_endpoint, ::grpc::InsecureChannelCredentials()));
发送rpc请求:
::grpc::ClientContext context;
context.set_deadline(
gpr_time_from_micros(call_timeout_.InMicroseconds(), GPR_TIMESPAN));
RpcRequest request;
RpcResponse response;
::grpc::Status grpc_status = stub_->Call(&context, request, &response);
/server.cc
grpc::ServerBuilder builder;
builder.AddListeningPort(endpoint, ::grpc::InsecureServerCredentials());
builder.RegisterService(&rpc_service);
std::unique_ptrgrpc::Server grpc_server_ = builder.BuildAndStart();
您期望看到什么?
网络重置后,客户应成功拨打电话。
您看到了什么?
客户端无法从服务器收到响应。
我们还应该了解您的项目/环境吗?
当重新建立网络连接并且客户端无法从服务器接收响应时,tcpdump会捕获客户端发送一些数据包。
在打开网络的情况下启动客户端和服务器,然后拔出网络的连接不会导致任何错误消息,直到尝试进行呼叫为止。这与在断开网络连接的情况下启动客户端和服务器时的结果相同。尝试拨打电话后,客户端将从IDLE
转换为CONNECTING
,然后开始在CONNECTING
和TRANSIENT_FAILURE
状态之间来回跳动(尝试以指数级的反向连接来重新连接)关闭),直到重新建立连接。
如果客户端在连接网络的情况下启动,但未发送请求并且网络断开,则服务器不会收到客户端断开的错误。在拨打电话之前,客户将停留在"IDLE"
中。
如果客户端初始化并且在断开连接的网络上进行呼叫,则客户端将进入CONNECTING
状态(指数回退最多2分钟,此时客户端将处于{{ 1}}状态)。连接网络后,下一次通道将进入TRANSIENT_FAILURE
状态,客户端将进入CONNECTING
状态时,将重新建立连接。此后,每个呼叫将成功,直到重置网络。
客户端处于READY
状态后断开网络连接不会使客户端脱离READY
状态。
总而言之:在未进行呼叫之前,无论网络状态如何,客户端都将保持READY
状态。拨打电话后,客户端将尝试通过进入"IDLE"
状态来建立连接。如果未找到连接,它将在CONNECTING
和CONNECTING
状态之间转换反弹。找到连接后,客户端将进入TRANSIENT_FAILURE
状态。从这里开始,如果连接断开,客户端将不会再次尝试进入READY
状态。
与我遇到的类似问题(已结束)
https://github.com/grpc/grpc/issues/16974
已知修补程序:
在每次通话中创建一个新频道。
修复尝试失败:
CONNECTING
问题:
网络重置后,客户端是否可以使用已创建的频道?
重置网络后是否必须重新启动频道?
注意::我在grpc github上打开了一张票,并且在5天内没有收到任何回复,所以我也在这里发布。链接到grpc github问题:https://github.com/grpc/grpc/issues/18554