实验1: 漏桶实例,流量控制,每秒cat10个字符 输出到标准输出
signal + alarm + pause + 信号打断阻塞的系统调用
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <signal.h>
#define BUFSIZE 10
static 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 <src_file> <dest_file>\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 <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <signal.h>
#define CPS 10
#define BUFSIZE CPS
#define BURST 100
static 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 <src_file> <dest_file>\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);
}