限速算法基于令牌桶算法
1)记最大速度单位为S,第一次发送开始时,记当前时间为T,记令牌桶初始化N=0, N最大值为2S,最小发送单位M=S/4,发送间隔I = 200ms
2)发送前记录当前时间为t,如果 S(t-T) + N >= 2S, 令N = 2S, T = t ,发送M数据,休眠I时间
3)发送前记录当前时间为t, 如果 M < S(t-T) + N < 2S,则发送M数据,休眠I时间
4)发送前记录当前时间为t,如果 S(t-T) + N < M, 则使N = N + S(t-T), 休眠I时间
5)如果数据全部发送完毕则结束
#define RATELIMIT_BURST_TIMES_DEFAULT (2) //2s
#define RATELIMIT_USLEEP_INTERVAL (200000) //200ms
#define RATELIMIT_MINTOKER_DIV_PARAM (4) //division parameter
typedef struct _RateLimitInfo
{
struct timeval StartTime;
uint8_t RateLimitBurstTimes;
uint64_t MaxSendRateBps;
uint64_t RateLimitToken;
uint64_t MinRateLimitToken; /* when Token is larger than minToken, then send data of MinRateLimitToken */
uint64_t SleepInterval;
uint64_t DataBuffSize;
uint64_t DataBuffCount;
char DataBuff[0];
}__attribute__((packed)) RateLimitInfo;
uint64_t
GetRateLimitValuebybps(
uint64_t MaxSendRatebps,
uint64_t UnitSize
)
{
uint64_t ret = 0;
uint64_t sendRateHostOrder = be64toh(MaxSendRatebps); //net order convert if needed
ret = sendRateHostOrder / 8;
if (ret % UnitSize > UnitSize / 2)
{
ret = ret - ret % UnitSize;
}
else
{
ret = ret - ret % UnitSize + UnitSize;
}
if (ret == 0)
{
ret = UnitSize;
}
return ret;
}
uint64_t
RateLimitGetMinLimitToken(
uint64_t MaxSendRateBps,
uint64_t UnitSize
)
{
uint64_t minRateLimitToken = MaxSendRateBps / RATELIMIT_MINTOKER_DIV_PARAM ;
minRateLimitToken = minRateLimitToken + UnitSize - minRateLimitToken % UnitSize;
return minRateLimitToken;
}
int
RateLimitInit(
uint64_t MaxSendRateBps,
uint64_t UnitSize,
RateLimitInfo** RateLimit
)
{
*RateLimit = malloc(sizeof(RateLimitInfo) + 1024 * 1024);
if (*RateLimit == NULL)
{
printf("Malloc memory for Ratelimit error!\n");
return -ENOMEM;
}
(*RateLimit)->RateLimitBurstTimes = RATELIMIT_BURST_TIMES_DEFAULT;
(*RateLimit)->MaxSendRateBps = MaxSendRateBps;
(*RateLimit)->DataBuffSize = 1024 * 1024; //1M
(*RateLimit)->DataBuffCount = 0;
(*RateLimit)->RateLimitToken = 0;
(*RateLimit)->SleepInterval = RATELIMIT_USLEEP_INTERVAL;
/* MinRateLimitToken as usual , shoule be smaller or equal than DataBuffSize*/
(*RateLimit)->MinRateLimitToken = RateLimitGetMinLimitToken(MaxSendRateBps, UnitSize);
gettimeofday(&((*RateLimit)->StartTime), NULL);
return 0;
}
void
UpdateRateLimitToken(
RateLimitInfo* RateLimit
)
{
struct timeval currentTime;
uint64_t diff = 0;
uint64_t tokenAddSize = 0;
if (RateLimit->SleepInterval)
{
usleep(RateLimit->SleepInterval);
}
gettimeofday(¤tTime, NULL);
diff = (currentTime.tv_sec - (RateLimit->StartTime).tv_sec) * 1000 + (currentTime.tv_usec - (RateLimit->StartTime).tv_usec) / 1000;
tokenAddSize = diff * RateLimit->MaxSendRateBps / 1000;
RateLimit->RateLimitToken = RateLimit->RateLimitToken + tokenAddSize;
if (RateLimit->RateLimitToken < RateLimit->MinRateLimitToken)
{
RateLimit->SleepInterval = RATELIMIT_USLEEP_INTERVAL;
goto CommonReturn;
}
else
{
memcpy(&RateLimit->StartTime, ¤tTime, sizeof(currentTime));
}
CommonReturn:
return;
}
void RateLimitFree(RateLimitInfo* RateLimit)
{
free(RateLimit);
}
使用:
int
SendUnitDataWithRateLimit(
int Sockfd,
RateLimitInfo* RateLimit
)
{
int ret = 0;
int64_t sendSize = 0;
for(;;)
{
UpdateRateLimitToken(RateLimit);
while (RateLimit->RateLimitToken >= RateLimit->MinRateLimitToken && RateLimit->RateLimitToken >= Conn->UnitSize)
{
/*Do your send function*/
sendSize = send_func(SockFd, (char *)RateLimit->DataBuff, RateLimit->RateLimitToken);
RateLimit->RateLimitToken -= sendSize;
/*Do your exit logic*/
}
}
CommonReturn:
return ret;
}