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:統(tǒng)計周期,read長度到了指定閾值, 觸發(fā)限速統(tǒng)計
5 // lamt: 一次統(tǒng)計周期內, read了多少長度
6 struct timeval bwstart, bwend; // bwstart: 統(tǒng)計周期之開始時間
7 // bwend: 統(tǒng)計周期之結束時間
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; // 初始化統(tǒng)計周期
15 bw->lamt = 0; // 初始化當前read長度
16 timerclear(&bw->bwstart); // 初始化統(tǒng)計開始時間
17 timerclear(&bw->bwend); // 初始化統(tǒng)計結束時間
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 // 設置統(tǒng)計開始時間, 為當前時間
26 if (!timerisset(&bw->bwstart)) {
27 gettimeofday(&bw->bwstart, NULL);
28 return;
29 }
30
31 // 設置當前read長度
32 bw->lamt += read_len;
33 // 判斷當前read長度是否到達統(tǒng)計周期的閾值
34 if (bw->lamt < bw->thresh)
35 return;
36
37 // 設置統(tǒng)計結束時間,為當前時間
38 gettimeofday(&bw->bwend, NULL);
39 // bwend變量復用, 這個時候, bwend含義為, 本次統(tǒng)計周期實際開銷的時間: 既read thresh長度字節(jié),花了多少時間.
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含義為, 本次統(tǒng)計周期理論開銷的時間
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 // 如果差值達到了秒級, 則需要降低統(tǒng)計周期閾值, 確保統(tǒng)計相對精確
58 // thresh變?yōu)樵鹊?/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毫秒, 則需要加大統(tǒng)計周期閾值, 確保統(tǒng)計相對精確
65 // thresh變?yōu)樵鹊?倍, 但不能高于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 // 新的統(tǒng)計周期開始, 初始化lamt, bwstart變量
82 bw->lamt = 0;
83 gettimeofday(&bw->bwstart, NULL);
84 }