美文网首页
令牌桶封装成库示例

令牌桶封装成库示例

作者: 静倚晴窗笑此生 | 来源:发表于2019-03-24 19:20 被阅读0次

token_bucket.h文件(主要用来函数声明)

#ifndef __TOKEN_BUCKET_H
#define __TOKEN_BUCKET_H
/*
 * 实现令牌桶
 *      token  令牌
 *      cps    速率
 *      burst  上限
 */

#define TBF_MAX    1024

//创建令牌桶
int tbf_init(int cps, int burst);

//取令牌
int tbf_fetch(int id, int size);

//还令牌
int tbf_return(int id, int size);

//销毁令牌桶
int tbf_destory(int id);

#endif

token_bucket.c文件

#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>
#include <sys/time.h>
#include "token_bucket.h"

//定义桶的类型
struct tbf_st
{
    int cps;
    int burst;
    int token;
};

//定义1024的数组存桶的结构体地址
static struct tbf_st *line[TBF_MAX];
static int inited = 0;
struct sigaction oldact;
struct itimerval olditv;

//模块卸载,信号行为和时钟恢复
static void  mouder_unload(void)
{
    sigaction(SIGALRM, &oldact, NULL);
    setitimer(ITIMER_REAL, &olditv, NULL);
}

/******************************************/
static void alrm_handler(int s)
{
    for(int i=0; i<TBF_MAX; i++)
    {
        if(line[i] != NULL)
        {
            line[i] -> token += line[i] -> cps;
            if(line[i]->token >= line[i] -> burst)
                line[i] -> token = line[i] -> burst;
        }
    }
}

static void mouder_load(void)
{
    struct sigaction act;
    struct itimerval itv;

    act.sa_handler = alrm_handler;
    act.sa_flags = 0;
    sigemptyset(&act.sa_mask);
    
    sigaction(SIGALRM, &act, &oldact);
    
    itv.it_interval.tv_sec = 1;
    itv.it_interval.tv_usec = 0;

    itv.it_value.tv_sec = 1;
    itv.it_value.tv_usec = 0;

    setitimer(ITIMER_REAL, &itv, &olditv);

    atexit(mouder_unload);
}


//创建令牌桶
int tbf_init(int cps, int burst)
{
    struct tbf_st *new;
    int i;

    if(inited == 0)
    {
        mouder_load();
        inited = 1;
    }

    //找空位
    for(i=0; i<TBF_MAX; i++)
    {
        if(line[i] == NULL)
            break;
        return -1;
    }

    new = malloc(sizeof(*new));
    if( new == NULL)
        return -1;

    new->token = 0;
    new->cps = cps;
    new->burst = burst;

    line[i] = new;

    return i;
}

/**********************************************/
//找最小值
static int min(int a,int b)
{
    return a>b?a:b;
}

//取令牌
int tbf_fetch(int id, int size)
{
    int n;
    if(size <= 0)
        return -1;
    while(line[id]->token <= 0)
    {
        pause();
    }

    //取两者最小
    n = min(line[id]->token,size);

    line[id]->token -= n;

    return 0;
}
/**********************************************/

//还令牌
int tbf_return(int id, int size)
{
    if(size <= 0)
        return -1;
    line[id]->token += size;
    if(line[id]->token > line[id]->burst)
        line[id]->token = line[id]->burst;
    return size;
}

//销毁令牌桶
int tbf_destory(int id)
{
    if(id < 0 || id > TBF_MAX-1)
    {
        return -1;
    }
    free(line[id]);
    line[id] = NULL;
    return 0;
}

调试文件main.c

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <signal.h>
#include <errno.h>
#include <stdlib.h>

#include "token_bucket.h"

#define BUFSIZE 10
#define CPS BUFSIZE 
#define BURST CPS*10

int main(int argc, char **argv)
{
    int rfd, wfd;
    char buf[BUFSIZE] = {};
    int cnt, ret, pos;
    int tb,n;

    if (argc < 2) 
    {
        fprintf(stderr, "Usage....\n");
        return 1;
    }

    while (1) 
    {
        rfd = open(argv[1], O_RDONLY);
        if (rfd == -1) 
        {
            if (errno == EINTR)
            {
                // 信号打断---》假错
                continue;
            }
            perror("open()"); // 输出到标准错误输出
            return 1;
        }
        break;
    }

    tb = tbf_init(CPS, BURST);

    if(tb < 0)
    {
        fprintf(stderr, "tbf_init():");
        exit(1);
    }

    wfd = 1;

    while (1)
    {
        n = tbf_fetch(tb, CPS);
        if(n < 0)
        {
            fprintf(stderr, "tbf_fetch():");
            goto ERROR1;
        }

        cnt = read(rfd, buf, CPS); // 阻塞
        if (-1 == cnt) {
            if (errno == EINTR)
                continue;
            perror("read()");
            goto ERROR1;
        }
        if (0 == cnt) {
            // rfd结束标志
            break;
        }
        pos = 0;
        while (1) {
            ret = write(wfd, buf+pos, cnt);
            if (ret < 0) {
                if (errno == EINTR)
                    continue;
                perror("write()");
                goto ERROR1;
            }
            cnt -= ret;
            if (cnt > 0) {
                // 没写完
                pos += ret;
            } else {
                break;
            }
        }
    }

    tbf_destory(tb);

    close(rfd);

    return 0;
ERROR1:
    close(rfd);
    return 1;
}

makefile文件

SRC=main.o token_bucket.o
OBJ=tbf

$(OBJ):$(SRC)
    gcc -o $@ $^

clean:
    rm *.o $(OBJ)

相关文章

  • 令牌桶封装成库示例

    token_bucket.h文件(主要用来函数声明) token_bucket.c文件 调试文件main.c ma...

  • Nginx 限流配置(转)

    限流算法: 1. 令牌桶算法 算法思想是: 令牌以固定速率产生,并缓存到令牌桶中;令牌桶放满时,多余的令牌被丢弃;...

  • Nginx限流配置(转载)

    1、限流算法 令牌桶算法 算法思想是:a、令牌以固定速率产生,并缓存到令牌桶中;b、令牌桶放满时,多余的令牌被丢弃...

  • nginx限流算法

    1 限流算法 1.令牌桶 算法思想:*令牌以固定速率产生,并缓存到令牌桶中;*令牌桶放满时,多余的令牌被丢弃;*请...

  • 流控的那些事儿

    令牌桶算法令牌桶控制基于令牌桶是否存在令牌可以发送流量,每一个令牌是一个字节。当请求过来会消耗桶内中的令牌。另一边...

  • 令牌桶算法

    1、桶中每秒放入r个令牌 2、桶中最多能放入b个令牌,当令牌到达时令牌桶已经满了,令牌将被丢弃或放入缓存中 3、当...

  • 流量控制

    该库是基于令牌桶算法实现的 import "github.com/juju/ratelimit"var token...

  • 漏桶算法与令牌桶算法的区别

    令牌桶算法是通过控制令牌生成的速度进行限流,漏桶算法是控制请求从桶中流出的速度进行限流。简单理解为:令牌桶控制进,...

  • 【5分钟背八股】令牌桶限流算法是什么?

    令牌桶算法,是增加一个大小固定的容器,也就是令牌桶,系统以恒定的速率向令牌桶中放入令牌,如果有客户端来请求,先需要...

  • 令牌桶

    对于很多应用场景来说,除了要求能够限制数据的平均传输速率外,还要求允许某种程度的突发传输。这时候漏桶算法可能就不合...

网友评论

      本文标题:令牌桶封装成库示例

      本文链接:https://www.haomeiwen.com/subject/otfpvqtx.html