使用c语言实现传输的流量控制

在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].

你可能感兴趣的:(linux,c++&c,c语言,c++,开发语言)