限速算法基于令牌桶算法

限速算法基于令牌桶算法
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(&currentTime, 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, &currentTime, 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;
}

猜你喜欢

转载自blog.csdn.net/vegeta852/article/details/109580994
今日推荐