
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); }
发表评论
最新留言
路过按个爪印,很不错,赞一个!
[***.219.124.196]2025年03月30日 12时29分47秒
关于作者

喝酒易醉,品茶养心,人生如梦,品茶悟道,何以解忧?唯有杜康!
-- 愿君每日到此一游!
推荐文章
E28 LoRa模块透传 定点传输 RSSI测试与MicroPython应用
2021-05-08
抽离css文件
2021-05-08
babel预设、插件和webpack中运行
2021-05-08
Vue学习—深入剖析渲染函数
2021-05-08
Vue学习—深入剖析函数式组件
2021-05-08
基于selenium的分布式爬虫-微浏览器
2021-05-08
网络编程一 tcp的一些信号处理
2021-05-08
简单Makefile的编写
2021-05-08
使用BAT批处理 匹配查找指定文件夹,并在当文件夹下创建空文件
2021-05-08
wxpython的Hello,World代码探索
2021-05-08
IDEA出现错误:找不到或无法加载主类 io.xxx.XXXApplication
2021-05-08
【数字图像处理】OpenCV3 学习笔记
2021-05-08
【单片机开发】智能小车工程(经验总结)
2021-05-08
【单片机开发】基于stm32的掌上游戏机设计 (项目规划)
2021-05-08
【单片机开发】基于stm32的掌上游戏机设计(终章)
2021-05-08
PHP编译步骤参考和FASTCGI方式(PHP-FPM)配置PHP
2021-05-08
iptables NAT表之SNAT、DNAT、REDIRECT介绍
2021-05-08
KeepAlived介绍、配置示例、KeepAlived配置IPVS、调用脚本进行监控
2021-05-08