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

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

在linux 环境下,利用令牌实现文件的的读取,并把相应的内容写入终端。

在这个过程中通过令牌的机制来实现流量的控制,并且在程序执行的过程中要考虑到执行过程中被打断的情况,同时不能使得数据出现丢失

main.c

#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <signal.h>
#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 <stdio.h>
#include <stdlib.h>
#include "sig_token.h"
#include <errno.h>
#include <signal.h>
#include <unistd.h>
typedef void (*sighandler_t)(int);
static sighandler_t sighandler_save;
#define MTOKEN_MAX 1024
//为了不让用户看到我的数据结构,我把mtoken定义在 .c 文件中
struct mtoken{int cps;//每个信号的到来,就+10int burst;//最多到100int 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;i<MTOKEN_MAX;i++){if(job[i] == NULL){return i;}}return -1;
}
static void signal_handler(int s){//信号相应函数alarm(1);int i;for(i=0;i<MTOKEN_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){//在module_load函数发生故障的时候,调用,用于free掉存放mtoken 的指针数组jobsignal(SIGALRM,sighandler_save);alarm(0);int i;for(i=0;i<MTOKEN_MAX;i++){free(job[i]);}
}
static void module_load(void){//发信号的函数,sighandler_save = signal(SIGALRM,signal_handler);alarm(1);init = 1;atexit(module_unload);
}mtoken *mytoken_init(int cps,int burst){struct mtoken * me;int pos;//为了这个过程中调用mytoken_init 函数只会发生一次module(防止alarm冲突)设置一个全局变量init来管控if(!init){module_load();}pos = get_index();if(pos < 0){return NULL;}me = malloc(sizeof(*me));if(me == NULL){return me;}me->cps = 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){//释放mtokenstruct 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 <stdio.h>
#include <stdlib.h>
#include "sig_token.h"
#include <errno.h>
#include <signal.h>
#include <unistd.h>
#include <sys/time.h>
// 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;//每个信号的到来,就+10int burst;//最多到100int 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;i<MTOKEN_MAX;i++){if(job[i] == NULL){return i;}}return -1;
}
static void sigaction_handler(int s,siginfo_t *info,void *nouse){//信号相应函数if(info->si_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;i<MTOKEN_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){//在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;i<MTOKEN_MAX;i++){free(job[i]);}
}
static void module_load(void){//发信号的函数,//sighandler_save = signal(SIGALRM,signal_handler);//alarm(1);struct sigaction sa;sigemptyset(&sa.sa_mask);sa.sa_sigaction = sigaction_handler;sa.sa_flags = SA_SIGINFO;sigaction(SIGALRM,&sa,&sigaction_save);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);init = 1;atexit(module_unload);
}mtoken *mytoken_init(int cps,int burst){struct mtoken * me;int pos;//为了这个过程中调用mytoken_init 函数只会发生一次module(防止alarm冲突)设置一个全局变量init来管控if(!init){module_load();}pos = get_index();if(pos < 0){return NULL;}me = malloc(sizeof(*me));if(me == NULL){return me;}me->cps = 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){//释放mtokenstruct mtoken *metoken = ptr;job[metoken->pos] = NULL;free(ptr);printf("free\n");return 0;
}

写的没有那么详细,请见谅,如有疑问欢迎留言或者邮件755465928@qq.com.

http://www.xdnf.cn/news/11280.html

相关文章:

  • 大数的四则运算-(加法、减法、乘法、除法)
  • 高通 MSM 8916与MSM8926芯片的区别
  • 磁盘文件系统Fat、Fat32、NTFS、exFAT的优缺点
  • 【硬件设计】DC-DC之降压(BUCK)电路
  • HTML(Hyper Text Mark-up Language )即超文本标记语言
  • 药学【11】
  • ConnectionString 属性尚未初始化。问题的最直接解决方案!
  • to_char 详解
  • 利用aapt.exe查看apk的信息
  • 毕业答辩PPT制作和讲述要点(整理)
  • 什么是局域网(内网)?什么是广域网(外网)?
  • CSS网页制作布局实例教程
  • iheartradio android,最牛电台iHeartRadio
  • 使用PHP实现页面跳转和分页功能
  • 非常详细的启动光盘制作教程-菜鸟版
  • 存储过程语法及实例
  • 【Android】SDK安装及配置
  • 软件设计中的易用性
  • python网页爬虫之re库及正则表达式(含实例)
  • 国内优质堡垒机厂商大揭秘!你知多少!
  • 使用AntiSamy防范XSS跨站脚本攻击
  • 获取流媒体地址
  • android:layout_height fill_parent,如何区分Android wrap_content和fill_parent的详细说明
  • 数字化体育:运动员的训练数据分析
  • ASSSDBenchmark简述
  • mencoder的配置文件
  • Turbo Pascal简介
  • .net反编译工具Reflector
  • Linux常用命令——tftp命令
  • 英语单词音近形似转化规律研究