当前位置: 首页 > news >正文

令牌桶C语言代码实现

令牌桶实例

令牌桶三要素

cps 每秒钟传输字节数

burst 令牌桶内最多能传输的字节数,token的最大值

token 令牌的个数

之前是一个令牌(token)对应一个字节,现在将一个token变为一个cps,cps是解码速率,每攒到一个令牌,就token+=cps

不同的速率使用不同的令牌桶,将令牌桶存储在一个数组中。

代码

mytbf.h

#ifndef MYTBF__H_
#define MYTBF__H_#define MYTBF_MAX	1024
typedef void mytbf_t;mytbf_t *mytbf_init(int cps,int burst);int mytbf_fetchtoken(mytbf_t * ,int);int mytbf_returntoken(mytbf_t * ,int );int mytbf_destroy(mytbf_t *);#endif

mytbf.c

#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <signal.h>#include "mytbf.h"typedef void (*sighandler_t)(int);//将令牌桶的数据结构存在数组中
static struct mytbf_st * job[MYTBF_MAX];
static int inited = 0;
#define MIN(A,B) (A < B ? A : B)
static sighandler_t alrm_handler_save;/*每个token代表一个字节,cps代表解码速率,burst应该是cps的倍数,token=token+cps*/
//这是令牌桶的数据结构,这个数据结构存在数组中
struct mytbf_st 
{int cps;	//每秒钟传输的字节数int burst;	//令牌桶中令牌最大数量int token;	//令牌的个数int pos;	//记录令牌桶在数组的位置下标
};//信号捕捉函数
static void alrm_handler(int s)
{alarm(1);//为数组中的令牌桶中的令牌做累计for(int i = 0;i < MYTBF_MAX; i++){if(job[i] != NULL){job[i]->token += job[i]->cps;if(job[i]->token > job[i]->burst)job[i]->token = job[i]->burst;}}
}
//关闭时钟发送信号,恢复
static void module_unload(void)
{int i;//恢复SIGALRM到之前的功能signal(SIGALRM,alrm_handler_save);//取消时钟发送信号alarm(0);//释放令牌桶for(i = 0;i < MYTBF_MAX;i++){free(job[i]);}}
//第一次发时钟信号的函数
static void module_load(void)
{//signal的返回值是注册新的行为之前的行为alrm_handler_save = signal(SIGALRM,alrm_handler);alarm(1);//注册钩子函数,这个不是函数调用,而是当调用exit的时候才会调用atexit(module_unload);
}static int get_free_pos(void)
{int i = 0;for(i = 0;i < MYTBF_MAX; i++){if(job[i] == NULL)return i;}return -1;
}mytbf_t *mytbf_init(int cps,int burst)
{int pos = 0;struct mytbf_st *me;//在数组中找到空位下标pospos = get_free_pos();if(pos < 0){return NULL;}if( !inited ){module_load();inited = 1;}me = malloc(sizeof(*me));if(me == NULL){return NULL;}//初始化令牌桶结构体成员me->token = 0;me->cps = cps;me->burst = burst;me->pos = pos;//将令牌桶放到数组中job[pos] = me;return me;
}//取令牌
int mytbf_fetchtoken(mytbf_t *ptr ,int size)
{int n;struct mytbf_st *me = ptr;if(size <= 0)return -1;while(me->token <= 0)pause();//当要取的令牌数大于最大令牌数量,给最大令牌数量n = MIN(me->token,size);me->token -=n;return n;}//归还令牌
int mytbf_returntoken(mytbf_t *ptr ,int size)
{struct mytbf_st *me = ptr;if(size <=0 )return -1;me->token +=size;if(me->token > me->burst)me->token = me->burst;return size;
}//销毁令牌桶
int mytbf_destroy(mytbf_t *ptr)
{	//因为mytbf_t 是void类型,转换下struct mytbf_st *me = ptr;job[me->pos] = NULL;free(me);return 0;
}

main.c

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <signal.h>
#include <errno.h>
#include "mytbf.h"#define CPS	    10
#define BUFSIZE	1024
#define BURST   100int main(int argc,char**argv)
{int sfd,dfd = 1;int size,errnor;char buf[BUFSIZE];int len,ret,pos;mytbf_t * tbf;if(argc < 2){fprintf(stderr,"Usage ....\n");exit(1);}//初始化令牌桶tbf = mytbf_init(CPS,BURST);//打开要读取的文件do{sfd = open(argv[1],O_RDONLY);if(sfd < 0){if(errno != EINTR){perror("open()");exit(1);}}}while(sfd < 0);while(1){size = mytbf_fetchtoken(tbf,BUFSIZE);if(size < 0){fprintf(stderr,"mytbf_fetchtoken is error\n");exit(1);}while((len = read(sfd,buf,size)) < 0){if(errno == EINTR)continue;perror("read()");break;}if(len == 0)break;//判断令牌是否用完if(size - len > 0)mytbf_returntoken(tbf,size-len);pos = 0;//使用循环读,因为是向终端写while(len > 0){ret = write(dfd,buf+pos,len);if(ret < 0){	//假错,继续读if(ret == EINTR)continue;perror("write()");exit(1);}pos += ret;len -= ret;}}mytbf_destroy(tbf);exit(0);
}

makefile

all:mytbf
mytbf:main.o mytbf.ogcc $^ -o $@
clean:rm *.o mytbf
http://www.lryc.cn/news/136053.html

相关文章:

  • Mybatis 建立依赖失败:报错Dependency ‘mysql:mysql-connector-java:8.0.28‘ not found
  • 多线程+隧道代理:提升爬虫速度
  • 使用@Configuration和@Bean给spring容器中注入组件
  • 信号波形解读
  • Centos 解决 XXX不在 sudoers 文件中。此事将被报告。的错误
  • 雪花算法和uuid的区别
  • docker之DockerFile与网络
  • 知识蒸馏开山之作(部分解读)—Distilling the Knowledge in a Neural Network
  • centos 7 安装 docker-compose curl 设置代理
  • 3D姿态相关的损失函数
  • ChatGPT取代人类仍然是空想?有没有一种可能是AI在迷惑人类
  • 基于swing的旅游管理系统java jsp旅行团信息mysql源代码
  • Windows wsl2支持systemd
  • NLP - 如何解决ModuleNotFoundError: No module named ‘jieba‘的问题
  • Windows10上VS2022单步调试FFmpeg 4.2源码
  • 【tkinter 专栏】菜单组件
  • 【LeetCode-经典面试150题-day10】
  • Transformer在医学影像中的应用综述-分类
  • 新服务器基本环境下载conda + docker + docker-compose + git
  • Matlab论文插图绘制模板第108期—特征渲染的标签散点图
  • 设计模式之中介者模式(Mediator)的C++实现
  • css弹性布局的方式
  • 阿里云源 Python、npm、git、goproxy
  • 微服务架构1.0
  • iOS开发Swift-基础部分
  • 【LeetCode-经典面试150题-day11】
  • 深度学习入门(三):卷积神经网络(CNN)
  • 网站是如何识别网络爬虫的?
  • TP-Link 智能灯泡缺陷能让黑客窃取用户 WiFi 密码
  • 接口测试,如何测试?