SUN RPC是对socket的封装,其底层适用TCP或是UDP协议来传输数据,本文讨论SUN RPC使用的超时和重传策略。
1. 总超时值:一个客户端等待其服务器的应答的总时间量。TCP和UDP都是用该值;
2. 重试超时:只用于UDP, 是一个客户等待其服务器的应答期间每次重传请求的间隔时间;
注:因TCP是可靠的面向连接的协议,有自己的一套机制来保证端到端的传输可靠性,故使用TCP建立的应用不需要考虑超时重传等问题。
默认的超时时间可以通过clnt_control函数获取,
clnt = clnt_create (host, square_prog, square_vers, "udp");
struct timeval tv;
clnt_control(clnt, CLGET_TIMEOUT, (char *)&tv);
printf("timeout = %d : timout = %d\n", tv.tv_sec, tv.tv_usec);
clnt_control(clnt, CLGET_RETRY_TIMEOUT, (char *)&tv);
printf("timeout = %d : timeout = %d\n", tv.tv_sec, tv.tv_usec);
其中,UDP的默认总超时值为-1,重传超时值为5s(unp书上说是15s);
TCP的默认总超时值为0(unp书上说是30s);
跟书上不同的地方应该是由于RPC的版本不同吧。
为了对这些数据进行验证,以square程序为例,通过改变clnt_call传递的TIMEOUT值及服务器端处理请求前的睡眠时间值,我做了几个实验:(超时值还可以通过clnt_control来指定,此时rpc_call忽略参数timeout)
1. TIMEOUT = {2,0},服务器端睡眠10s,使用tcp协议;
现象:客户端2s后提示call failed: rpc: time out,服务器接收到一次请求。
分析: 与期望相吻合,应用请求超过总的超时值时返回。
2. TIMEOUT = {2, 0}, 服务器端睡眠10s,使用udp协议;
现象:客户端5s后提示call failed: rpc: time out,服务器接收到一次请求。
分析:不明白,不是2s就提示超时么。
于是,我猜测是不是使用udp时,总的超时值不能小于重传时间呢?
做如下试验:通过clnt_control将UDP的重试时间改成10s,TIMEOUT值不变,仍为2s。
现象:客户端10s后提示call failed: rpc: time out,服务器接收到一次请求。
分析:我的猜测可能是正确的,RPC在实现时将总的超时值设为重传值和TIMEOUT中的较大值,不过这仅仅是猜测,没有看过SUN RPC实现的代码,不敢往下断言。
3. TIMEOUT = {25, 0}, 服务器睡眠10s,使用tcp协议;
现象:客户端10s后收到应答,服务器收到一次请求。
分析:与期望相符合,整个请求没有超出总的超时值。
4. TIMEOUT = {25, 0}, 服务器睡眠10s,使用udp协议;
现象:客户端在快到11s时收到一个回复,而服务器收到三次请求。
分析:
l 0s时,客户端启动后发送请求,服务器端接受该请求,处理时睡眠10s;
l 5s时,客户端重发请求,服务器端接受该请求,等待第一个请求处理完后。
l 10s时,客户端再次发送请求,服务器端接受该请求,等待前两次请求处理完.
不到1s后,客户端收到回复,这是服务器对第一个请求的应答,程序结束。
l 20s后,服务器端处理完第二个请求;
l 20s后,服务器端处理完第三个请求;
服务器睡眠10s就返回结果,为什么客户端会发出第三次请求?
因为网络延时,服务器从收到第一个请求,到睡眠10s,处理数据,返回结果时已经是10s之后的事情了,而客户端在10s时就发送了第三次请求,并马上收到了服务器对第一次请求的应答数据。
以上是我对SUN RPC超时和重传机制的一点理解,望不吝赐教!