SCP限速逻辑实现--带中文注释的bandwidth_limit函数
SCP支持限速, 通过-l参数, 指定拷贝的速度
-l limit
Limits the used bandwidth, specified in Kbit/s.
具体实现, 是在misc.c中的bandwidth_limit函数
下面附上带中文注释的bandwidth_limit函数代码
1 struct bwlimit {
2 size_t buflen; // 每次read的buf长度
3 u_int64_t rate, thresh, lamt; // rate: 限速速率, 单位kpbs
4 // thresh:统计周期,read长度到了指定阈值, 触发限速统计
5 // lamt: 一次统计周期内, read了多少长度
6 struct timeval bwstart, bwend; // bwstart: 统计周期之开始时间
7 // bwend: 统计周期之结束时间
8 };
9
10 void bandwidth_limit_init(struct bwlimit *bw, u_int64_t kbps, size_t buflen)
11 {
12 bw->buflen = buflen; // 初始化read buf长度
13 bw->rate = kbps; // 初始化限速速率
14 bw->thresh = bw->rate; // 初始化统计周期
15 bw->lamt = 0; // 初始化当前read长度
16 timerclear(&bw->bwstart); // 初始化统计开始时间
17 timerclear(&bw->bwend); // 初始化统计结束时间
18 }
19
20 void bandwidth_limit(struct bwlimit *bw, size_t read_len)
21 {
22 u_int64_t waitlen;
23 struct timespec ts, rm;
24
25 // 设置统计开始时间, 为当前时间
26 if (!timerisset(&bw->bwstart)) {
27 gettimeofday(&bw->bwstart, NULL);
28 return;
29 }
30
31 // 设置当前read长度
32 bw->lamt += read_len;
33 // 判断当前read长度是否到达统计周期的阈值
34 if (bw->lamt < bw->thresh)
35 return;
36
37 // 设置统计结束时间,为当前时间
38 gettimeofday(&bw->bwend, NULL);
39 // bwend变量复用, 这个时候, bwend含义为, 本次统计周期实际开销的时间: 既read thresh长度字节,花了多少时间.
40 timersub(&bw->bwend, &bw->bwstart, &bw->bwend);
41 if (!timerisset(&bw->bwend))
42 return;
43
44 // 将单位从Byte变成bit
45 bw->lamt *= 8;
46 // 根据限速速率, 计算理论应该花费多少时间
47 waitlen = (double)1000000L * bw->lamt / bw->rate;
48 // bwstart变量复用, 这个时候, bwstart含义为, 本次统计周期理论开销的时间
49 bw->bwstart.tv_sec = waitlen / 1000000L;
50 bw->bwstart.tv_usec = waitlen % 1000000L;
51
52 // 如果理论开销时间 > 实际开销时间, 则需要做限速
53 if (timercmp(&bw->bwstart, &bw->bwend, >)) {
54 // bwend变量复用, 这个时间, bwend含义为, 理论开销时间 和 实际开销时间的差值, 既需要sleep的时间, 确保达到限速到指定的rate值
55 timersub(&bw->bwstart, &bw->bwend, &bw->bwend);
56
57 // 如果差值达到了秒级, 则需要降低统计周期阈值, 确保统计相对精确
58 // thresh变为原先的1/2, 但不能低于buflen的1/4
59 if (bw->bwend.tv_sec) {
60 bw->thresh /= 2;
61 if (bw->thresh < bw->buflen / 4)
62 bw->thresh = bw->buflen / 4;
63 }
64 // 如果差值小于10毫秒, 则需要加大统计周期阈值, 确保统计相对精确
65 // thresh变为原先的2倍, 但不能高于buflen的8倍
66 else if (bw->bwend.tv_usec < 10000) {
67 bw->thresh *= 2;
68 if (bw->thresh > bw->buflen * 8)
69 bw->thresh = bw->buflen * 8;
70 }
71
72 // 乖乖的睡一会吧, 以达到限速目的
73 TIMEVAL_TO_TIMESPEC(&bw->bwend, &ts);
74 while (nanosleep(&ts, &rm) == -1) {
75 if (errno != EINTR)
76 break;
77 ts = rm;
78 }
79 }
80
81 // 新的统计周期开始, 初始化lamt, bwstart变量
82 bw->lamt = 0;
83 gettimeofday(&bw->bwstart, NULL);
84 }