令牌桶封装成库示例

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)
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 218,640评论 6 507
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,254评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 165,011评论 0 355
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,755评论 1 294
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,774评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,610评论 1 305
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,352评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,257评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,717评论 1 315
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,894评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,021评论 1 350
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,735评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,354评论 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,936评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,054评论 1 270
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,224评论 3 371
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,974评论 2 355

推荐阅读更多精彩内容

  • 稀缺是永恒的,而短缺和过剩都是价格受到人为干预的结果。 当价格过低的时候,人们不得不展开价格以外的竞争方...
    钟树堂阅读 712评论 0 1
  • 今天又再一次深深地体会到,我们做人有空杯心是多么的重要。其实我们每天早上做的第一件事情是什么,我们肯定是先去上卫生...
    林玉珍阅读 380评论 0 1
  • 我这个人,自尊心很强,但能力一般,意志力又差,没有什么过人之处,可以总结为死要面子的屌丝一枚。这就很矛盾了,没实力...
    皮德拉阅读 356评论 6 3
  • 在成年人的世界里,读书这一行为多少带有目的性和功利性。有时,我们阅读是为了实现自己的目标与理想,有时是为了提升...
    无涯的生活日志阅读 533评论 5 4
  • 教育故事----蹲下身子和孩子说话 题记:“冯博,如果在期末考试中语文、数学都考九十分以上,来找我,发奖...
    东原郡人阅读 655评论 0 1