在linux 环境下,利用令牌实现文件的的读取,并把相应的内容写入终端。
在这个过程中通过令牌的机制来实现流量的控制,并且在程序执行的过程中要考虑到执行过程中被打断的情况,同时不能使得数据出现丢失
main.c
#include
#include
#include
#include
#include
#include
#include
#include "sig_token.h"
#define CPS 10 //每隔一秒钟可以获得10个字符的传输权限,定义每个token每次传输一个字符。
#define BURST 100//令牌中最多可以有100个字符
#define MAXSIZE 5 //自己对传输的需要,这里为5个字符
int main(int argc,char **argv){
char buff[MAXSIZE];
if(argc < 2){
fprintf(stderr,"usage...");
exit(1);
}
int sfd,ret,len,path=0,size;
mtoken *mytoken;
sfd = open(argv[1],O_RDONLY);
if(sfd < 0){
exit(1);
}
mytoken = mytoken_init(CPS,BURST);//初始化mytoken cps=10 brust=100,token=0
if(mytoken == NULL){
exit(1);
}
while(1){
size = mytoken_fetch(mytoken,MAXSIZE);//申请token,准备传输数据。
if(size < 0){
exit(0);
}
len = read(sfd,buff,size);//在获得相应的令牌之后,读取相应的字符个数
if(len < 0){
break;
}
if(len == 0){
break;
}
if(size - len > 0){
mytoken_return(mytoken,size-len);
}
path = 0;
while(len>0){
ret = write(1,buff+path,len);//写入终端
if(ret < 0){
break;
}
len -= ret;//为了防止某些中断打断了向终端写入数据,而产生的数据丢失,这样数据必须传输完。
path+=ret;
}
}
close(sfd);
mytoken_destory(mytoken);
}
sig_token.c
#include
#include
#include "sig_token.h"
#include
#include
#include
typedef void (*sighandler_t)(int);
static sighandler_t sighandler_save;
#define MTOKEN_MAX 1024
//为了不让用户看到我的数据结构,我把mtoken定义在 .c 文件中
struct mtoken{
int cps;//每个信号的到来,就+10
int burst;//最多到100
int token;//令牌数
int pos;//记录该mtoken在job中的位置
};
static int init=0;
static struct mtoken* job[MTOKEN_MAX];//假设最多可以又1024个mtoken
static int get_index(void){
//该函数用于获得malloc到的mtoken需要存在的位置
int i;
for(i=0;itoken +=job[i]->cps;
if(job[i]->token >job[i]->burst){
job[i]->token = job[i]->burst;
}
}
}
}
static void module_unload(void){
//在module_load函数发生故障的时候,调用,用于free掉存放mtoken 的指针数组job
signal(SIGALRM,sighandler_save);
alarm(0);
int i;
for(i=0;icps = cps;
me->burst = burst;
me->token = 0;
me->pos = pos;
job[pos] = me;
return me;
}
int mytoken_return(mtoken *mytoken,int size){
//归还token的函数,在实际使用token,比申请的少的时候
struct mtoken *metoken = mytoken;
if(size <= 0){
return -EINVAL;
}
metoken->token +=size;
if(metoken->token > metoken->burst){
metoken->token = metoken->burst;
}
return 0;
}
int mytoken_fetch(mtoken *mytoken,int size){
//申请每次能够传输的字符数,
struct mtoken *metoken = mytoken;
while(!metoken->token){
pause();
}
if(metoken->token >=size){
metoken->token -= size;
return size;
}
else{
size = metoken->token;
metoken->token = 0;
return size;
}
}
int mytoken_destory(mtoken *ptr){
//释放mtoken
struct mtoken *metoken = ptr;
job[metoken->pos] = NULL;
free(ptr);
printf("free\n");
return 0;
}
sig_token.h
#ifndef SIG_TOKEN_H__
#define SIG_TOKEN_H__
typedef void mtoken;
mtoken *mytoken_init(int cps,int burst);
int mytoken_fetch(mtoken *,int);
int mytoken_return(mtoken *,int);
int mytoken_destory(mtoken*);
#endif
使用signal+alarm函数是不安全的(在程序的执行过程中,如果我从终端发送while true ;kill -ALRM **进程号**;done,会使得流量控制失效),所以我使用sigsaction +setitimer函数代替,改进了程序,使得程序只接受内核的时间,通过内核的发送的信号进行流量控制。
程序如下(只要改sig_token.c)
#include
#include
#include "sig_token.h"
#include
#include
#include
#include
// typedef void (*sighandler_t)(int);
// static sighandler_t sighandler_save;
static struct sigaction sigaction_save;
#define MTOKEN_MAX 1024
//为了不让用户看到我的数据结构,我把mtoken定义在 .c 文件中
struct mtoken{
int cps;//每个信号的到来,就+10
int burst;//最多到100
int token;//令牌数
int pos;//记录该mtoken在job中的位置
};
static int init=0;
static struct mtoken* job[MTOKEN_MAX];//假设最多可以又1024个mtoken
static int get_index(void){
//该函数用于获得malloc到的mtoken需要存在的位置
int i;
for(i=0;isi_code !=SI_KERNEL)
return ;
struct itimerval itv;
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,NULL);
int i;
for(i=0;itoken +=job[i]->cps;
if(job[i]->token >job[i]->burst){
job[i]->token = job[i]->burst;
}
}
}
}
static void module_unload(void){
//在module_load函数发生故障的时候,调用,用于free掉存放mtoken 的指针数组job
// signal(SIGALRM,sighandler_save);
// alarm(0);
// struct sigaction sa;
// sigemptyset(&sa.sa_mask);
// sa.sa_sigaction = sigaction_handler;
// sa.sa_flags = SA_SIGINFO;
sigaction(SIGALRM,&sigaction_save,NULL);
struct itimerval itv;
itv.it_interval.tv_sec = 0;
itv.it_interval.tv_usec = 0;
itv.it_value.tv_sec = 0;
itv.it_value.tv_usec = 0;
setitimer(ITIMER_REAL,&itv,NULL);
int i;
for(i=0;icps = cps;
me->burst = burst;
me->token = 0;
me->pos = pos;
job[pos] = me;
return me;
}
int mytoken_return(mtoken *mytoken,int size){
//归还token的函数,在实际使用token,比申请的少的时候
struct mtoken *metoken = mytoken;
if(size <= 0){
return -EINVAL;
}
metoken->token +=size;
if(metoken->token > metoken->burst){
metoken->token = metoken->burst;
}
return 0;
}
int mytoken_fetch(mtoken *mytoken,int size){
//申请每次能够传输的字符数,
struct mtoken *metoken = mytoken;
while(!metoken->token){
pause();
}
if(metoken->token >=size){
metoken->token -= size;
return size;
}
else{
size = metoken->token;
metoken->token = 0;
return size;
}
}
int mytoken_destory(mtoken *ptr){
//释放mtoken
struct mtoken *metoken = ptr;
job[metoken->pos] = NULL;
free(ptr);
printf("free\n");
return 0;
}
写的没有那么详细,请见谅,如有疑问欢迎留言或者邮件[email protected].