Linux系统编程46 信号 - 流量控制,通过漏桶,令牌桶实现
发布日期:2021-05-07 13:25:52 浏览次数:19 分类:精选文章

本文共 2634 字,大约阅读时间需要 8 分钟。

实验1: 漏桶实例,流量控制,每秒cat10个字符 输出到标准输出

signal + alarm + pause + 信号打断阻塞的系统调用

#include 
#include
#include
#include
#include
#include
#include
#include
#define BUFSIZE 10static volatile int loop = 0;static void alrm_handler(int s){ alarm(1);//重新定时 loop = 1;}int main(int argc,char *argv[]){ int sfd,dfd=1; char buf[BUFSIZE]; int len,ret,pos; if(argc < 2) { fprintf(stderr,"Usage:%s
\n",argv[0]); exit(1); } signal(SIGALRM,alrm_handler); alarm(1); do { sfd = open(argv[1],O_RDONLY); if(sfd < 0) { if(errno != EINTR)//防止是 信号打断阻塞的系统调用 { perror("open()"); exit(1); } } }while(sfd < 0); while(1) {//休眠挂起 直到收到信号,重新开始执行while(!loop)循环,实现一秒一输出// 这里也可以 不用pause(),while()后 执行空,但是这样 CPU 占用率会很高,一秒钟会在这里执行循环上亿次,所以用pause()替换,直接休眠等待信号来唤醒/* while(!loop) ;*/ while(!loop) pause(); loop = 0; while((len = read(sfd,buf,BUFSIZE)) < 0) { if(errno == EINTR)//防止是 信号打断阻塞的系统调用 continue; perror("read()"); break; } if(len == 0) break; //确保写进去 len 个字节 pos = 0; while(len > 0) { ret = write(dfd,buf+pos,len); if(ret < 0) { if(errno == EINTR) //防止是 信号打断阻塞的系统调用 continue; perror("write()"); exit(1); } pos += ret; len -= ret; } } close(sfd);}

缺点:

如果读取的是打印机类的设备,并且当时打印机上面没有数据,那么程序就会一直循环于 read处

while((len = read(sfd,buf,BUFSIZE)) < 0)		{	if(errno == EINTR)//防止是 信号打断阻塞的系统调用				continue;即 一直循环于: 读阻塞 ,打断阻塞 判断是假错误(信号打断阻塞的系统调用) 返回重新读 。。。。 读阻塞 ,打断阻塞 判断是假错误(信号打断阻塞的系统调用) 返回重新读 。。。。 读阻塞 ,打断阻塞 判断是假错误(信号打断阻塞的系统调用) 返回重新读 。。。。

所以 漏桶的缺陷就是 如果没有数据的时候 就会一直循环等待,直到有数据,如果忽然来的数据量很大,也不能快速的去读数据,只能慢慢的一秒10个字节的去读n次


令牌桶的优势,就是 当没有数据可读的时候,会积攒自己的权限,意思是 如果之前30秒一直没有数据,读空了30秒,那么就存下30个权限,等到有数据的时候,快速使用前面30个权限,快速连续读30次。

实验2:令牌桶实例

#include 
#include
#include
#include
#include
#include
#include
#include
#define CPS 10#define BUFSIZE CPS#define BURST 100static volatile int token = 0;static void alrm_handler(int s){ alarm(1); token++; if(token > BURST) token = BURST;}int main(int argc,char *argv[]){ int sfd,dfd=1; char buf[BUFSIZE]; int len,ret,pos; if(argc < 2) { fprintf(stderr,"Usage:%s
\n",argv[0]); exit(1); } signal(SIGALRM,alrm_handler); alarm(1); do { sfd = open(argv[1],O_RDONLY); if(sfd < 0) { if(errno != EINTR)//signal { perror("open()"); exit(1); } } }while(sfd < 0); while(1) { while(token <= 0) pause(); token--; while((len = read(sfd,buf,BUFSIZE)) < 0) { if(errno == EINTR)//signal continue; perror("read()"); break; } if(len == 0) break; //确保写进去 len 个字节 pos = 0; while(len > 0) { ret = write(dfd,buf+pos,len); if(ret < 0) { if(errno == EINTR) //signal continue; perror("write()"); exit(1); } pos += ret; len -= ret; } } close(sfd); }
上一篇:Linux系统编程47 信号 - setitimer(),优先使用setitimer()计时
下一篇:Linux系统编程45 信号 - kill() raise() alarm() pause()

发表评论

最新留言

路过按个爪印,很不错,赞一个!
[***.219.124.196]2025年03月30日 12时29分47秒