linux高编信号-------令牌桶实现
main.c
/********************************* *功能:每秒从文件读N个字节(N可控) *使用信号机制实现令牌桶:解决数据流不均匀传输 * *****************************/ #include <stdio.h> #include <stdlib.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <errno.h> #include <signal.h> #include <string.h> #include "mytbf.h" /*一次读写10个字符*/ #define CPS 10 #define BUFSIZE 1024 #define BURST 100//100次权限 int main(int argc ,char **argv) { int sfd ,dfd = 1 ; char buf[BUFSIZE]; int len ,ret , pos ; mytbf_t *tbf ; int size ; //1.判断输入参数 if(argc < 2) { fprintf(stderr , "Usage...\n"); exit(1); } //2.令牌桶初始化:返回值是令牌桶的指针 tbf = mytbf_init(CPS,BURST); if(tbf == NULL) { fprintf(stderr,"mytbf_init()failed !\n"); exit(1); } //3.打开文件 do { //3.1打开文件 sfd = open(argv[1],O_RDONLY); if(sfd < 0 ) { if(errno != EINTR)//判断不是被信号打断的错误情况 { perror("open()"); exit(1); } } }while(sfd < 0); //4.读文件(有令牌就可以读出来) while(1) { //4.1从令牌桶取令牌 size = mytbf_fetchtoken(tbf ,BUFSIZE); if(size < 0 ) { fprintf(stderr , "mytbf_fetchtoken():%s\n",strerror(-size)); exit(1); } //4.2读数据 while((len = read(sfd,buf,size)) < 0 ) { if(errno == EINTR) continue ; perror("read()"); exit(1); } if(len ==0) break; //4.3如果读出来的字符小于令牌的数量需要归还令牌 if(size - len > 0) mytbf_returntoken(tbf,size-len); pos = 0; //5.写数据 while(len > 0) { ret = write(dfd , buf+pos, len); if(ret < 0) { if(errno == EINTR) continue ; perror("write()"); exit(1); } pos+=ret ; len -=ret ; } sleep(1); } //6.关闭文件并且销毁当前令牌桶 mytbf_destroy(tbf); close(sfd); exit(0); }
mytbf.c
#include <stdio.h> #include <stdlib.h> #include <signal.h> #include "mytbf.h" #include <errno.h> typedef void(*sighandler_t)(int ); //令牌桶数组:存在令牌的地址 static struct mytbf_st* job[MYTBF_MAX]; //信号初始状态 static int inited = 0 ; static sighandler_t alrm_handler_save ; /*****令牌桶信息控制结构体****/ struct mytbf_st { int cps ;//每秒速率 int burst ;//最大保存令牌数量 int token ;//令牌数量 int pos ;//令牌桶的位置 }; /**************************** *功能:令牌桶数组里面找空位 *返回值:大于等于0空位下标;-1没有空位 * **************************/ static int get_free_pos(void) { int i ; for(i = 0 ; i < MYTBF_MAX ;i++) { if(job[i]==NULL) return i; } return -1 ; } /**********信号处理函数*********/ static void alrm_handler(int s) { int i ; //1.启动下次信号中断 alarm(1); for(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 int min(int a,int b) { if(a < b) return a ; return b ; } /********卸载模块**********/ static void module_unload(void) { int i ; signal(SIGALRM,alrm_handler_save); alarm(0); for(i = 0 ; i < MYTBF_MAX ;i++) free(job[i]); } /**********加载模块************/ static void module_load(void) { alrm_handler_save = signal(SIGALRM,alrm_handler); alarm(1); atexit(module_unload); } /******************************* *功能:创建令牌桶 *参数:cps:每秒读多少个字符个数 * burst:上限 *返回值:结构体的起始位置指针 * ****************************/ mytbf_t *mytbf_init(int cps , int burst) { struct mytbf_st *me ; int pos ; //1.第一次启动 if(inited == 0) { module_load(); inited = 1 ; } //2.找令牌桶数组的空位下标 pos = get_free_pos(); if(pos < 0) return NULL ; //3.初始化 me = malloc(sizeof(*me)); if(me == NULL) return NULL; me->token = 0 ; me->burst = burst ; me->cps = cps ; me->pos = pos ; //4.将 job[pos] = me ; return me ; } /******************************* *功能:获取令牌 *参数:ptr:令牌桶地址 * size:获取多少个令牌 *返回值:成功返回令牌数 * ****************************/ int mytbf_fetchtoken(mytbf_t *ptr ,int size ) { int n; struct mytbf_st *me = ptr ; if(size <= 0) return -EINVAL ; while(me->token <= 0) pause(); n = min(me->token,size); me->token -=n ; return n ; } /******************************* *功能:归还令牌 *参数:ptr:令牌桶地址 * size:归还令牌数量 *返回值:结构体的起始位置指针 * ****************************/ int mytbf_returntoken(mytbf_t * ptr,int size ) { struct mytbf_st *me = ptr ; if(size <=0) return -EINVAL ; me->token +=size ; if(me->token > me->burst ) me->token = me->burst ; return size ; } /******************************* *功能:删除令牌桶 *参数:ptr:删除的令牌桶地址 *返回值:无 * ****************************/ void mytbf_destroy(mytbf_t *ptr) { struct mytbf_st *me = ptr ; job[me->pos] = NULL ; free(ptr); }
mytbf.h
#ifndef MYTBF_H__ #define MYTBF_H__ #define MYTBF_MAX 1024//令牌桶的最大数量 typedef void mytbf_t ; int mytbf_fetchtoken(mytbf_t * ,int ); int mytbf_returntoken(mytbf_t * ,int ); int mytbf_destroy(mytbf_t *); #endif
Makefile
all:mytbf mytbf:main.o mytbf.o gcc $^ -o $@ clean: rm -rf *.o mytbf