防止客户端挂起

客户端可以通过两种方式挂起:网络连接可能导致服务器请求丢失,或者服务器本身可能崩溃。 使用默认选项时,RPC 永远不会超时调用,并且客户端线程将永远等待响应。

有两种方法可以阻止这种情况:保持活动状态和超时。

TCP 保持活动状态

客户端可以设置为定期 ping 服务器,以确保服务器处于活动状态且正在运行。 ping 是 ncacn_ip_tcpncacn_http 协议序列的 TCP 保持连接,因此它们在 CPU 利用率和网络带宽方面效率很高。 若要在给定的远程过程调用上启用保持活动状态,请在启动调用之前使用 RpcMgmtSetComTimeout 函数。 此函数采用绑定句柄和超时作为参数。 RpcMgmtSetComTimeout 使用提供的超时后,此绑定句柄上的每个远程过程调用。

RpcMgmtSetComTimeout 函数的 Timeout 参数指定 RPC 运行时间在打开前等待多长时间保持活动状态。 超时是介于 0 和 10 之间的值,其中 0 是最小超时值,10 是无限超时 (无超时) 。 超时本身不是以秒为单位;从提供给 RpcMgmtSetComTimeout 函数的超时值到秒的转换由 RPC 运行时完成,并且特定于实现。

下表提供了 Windows 2000 和 Windows XP 的秒数转换。 Windows 的未来版本可能会更改 Timeout 参数与超时值之间的映射(以秒为单位):

Timeout 参数 实际超时(以秒为单位)
0 (RPC_C_BINDING_MIN_TIMEOUT) 120
1 240
2 360
3 480
4 600
5 (RPC_C_BINDING_DEFAULT_TIMEOUT) 720
6 840
7 960
8 1080
9 (RPC_C_BINDING_MAX_TIMEOUT) 1200
10 (RPC_C_BINDING_INFINITE_TIMEOUT) 无限超时

 

启用 keep alives 后,客户端每秒发送一个保持活动状态的数据包。 如果服务器没有确认三个或更多个保持活动状态,则客户端将声明连接已死,并失败远程过程调用。 如果服务器在指定的超时时间内发送响应,则保持活动状态不会打开。 如果服务器响应保持活动状态,但不响应远程过程调用,则客户端将继续发送 keep alives。 服务器响应 RPC 调用后,将关闭保持活动状态。 对于 Windows 2000,仅对同步 RPC 调用启用保持活动状态。 对于 Windows XP,也为异步 RPC 调用打开了保持活动状态。

最好将 keep alives 设置为最低值,以确保客户端应用程序及时响应网络问题。 应仔细考虑这种诱惑,并审查是否有必要具有侵略性价值。 一旦恢复连接,暂时失去连接的服务器可能会发现自己被大量客户端保持活动状态。 此外,较长的计算任务可能需要两分钟以上,服务器可能会发现自己花费更多的 CPU 时间进行应答,而不是执行有用的工作。 因此,应将保持活动状态与节制一起使用。 如果客户端不能容忍其线程长时间被捆绑,则应考虑异步 RPC。

其他协议序列可能会实现不同的机制来检测无响应的服务器,具体取决于所使用的传输。 ncalrpc 传输不使用 keep alives。 由于 ncalrpc 中的所有通信都是本地通信,如果服务器在调用过程中变得无响应,客户端上的 RPC 运行时会立即使调用失败。

呼叫超时

如果网络连接断开或服务器崩溃,TCP 保持活动状态正常。 但是,如果服务器在用户模式下死锁,TCP 保持活动状态会成功返回,但调用永远不会返回。 为了应对此方案,为 Windows XP 添加了一个新的运行时选项:RPC_C_OPT_CALL_TIMEOUT。 此选项指示 RPC 运行时在每次向服务器发送请求时设置计时器。 如果计时器过期,则会自动取消调用并完成RPC_S_CALL_CANCELLED。 只要服务器在指定的时间限制内响应,客户端就不会取消调用。 这意味着多段调用可能需要超过超时期限才能完成,因为服务器的每个响应都在超时期限内收到,即使所有响应到达的时间段都超过超时期限。

此外,取消调用时,服务器不会收到取消通知。 因此,服务器可能会在某些时候执行调用,而客户端只会忽略来自服务器的响应。

调用超时的最危险陷阱是建立一个较短的超时,并在同一服务器上重试调用。 以下方案说明了此方法的危险:

假设有一个接近容量运行的服务器。 它有许多客户端的超时时间很短,例如 5 秒。 路由器的网络连接暂时中断或拥塞会导致服务器回复在几秒钟内失效。 在以太网网络上,这种情况很容易由服务器与另一台计算机共享的链接上的活动突发引起。 服务器无法在 5 秒超时之前发送所有答复。客户端取消其调用,并立即重试。 服务器不知道这些调用是重试的,并且也会执行这些调用。 因此,它执行了 30-50% 的调用,而不是执行其正常的调用工作负荷,具体取决于超时的客户端数。如果超出其容量,并且服务器无法在五秒内响应所有客户端,则会向服务器发送另一轮调用。 客户端会不断重新发出相同的调用,并且由于服务器在处理以前的调用时过载,因此无法在超时时间内做出响应。一旦响应,客户端就会超时,发出新的调用,并放弃应答。 在最坏的情况下,服务器在重新启动之前不会恢复,并且根据客户端访问模式,在停止足够数量的客户端之前可能无法恢复。

注意

调用超时仅适用于 ncacn_ip_tcpncacn_http 协议序列。