由实例一步一步演化:
1.先写一个简单的mycat出来,要求实现和cat一样的查看文件的功能
mycat.c
#include
#include
#include
#include
#include
#include
#include
#define SIZE 1024
int main(int argc,char *argv[])
{
char *buf[SIZE];
int n,fd;
if(argc<2)
{
fprintf(stderr,"Usage....");
exit(0);
}
fd = open(argv[1],O_RDONLY);
if(fd<0)
{
if(errno!=EINTR)//防止是 信号打断阻塞的系统调用
{
perror("open error\n");
exit(1);
}
}
while(1)
{
while((n = read(fd,buf,SIZE)) != EOF)
{
int x = write(1,buf,n);
if(x == 0)
{
exit(0);
}
}
}
exit(0);
close(fd);
}
-- 插入 --
2.将mycat稍微优化一下,防止出现write没有将read返回值全部写入的情况
mycatplus.c
#include
#include
#include
#include
#include
#include
#include
#define SIZE 1024
int main(int argc,char *argv[])
{
char *buf[SIZE];
int n,fd,len,pos,ret;
if(argc<2)
{
fprintf(stderr,"Usage....");
exit(0);
}
do{
fd = open(argv[1],O_RDONLY);
if(fd <0)
{
if(errno!=EINTR)
{
perror("open error\n");
exit(1);
}
}
}while(fd < 0);
while(1)
{
while((len = read(fd,buf,SIZE)) < 0)
{
if(errno==EINTR)
continue;
perror("read error\n");
exit(0);
}
if(len == 0)
break;
pos = 0;
while(len > 0)
{
ret = write(1,buf+pos,len);
if(ret < 0)
{
if(errno==EINTR)
continue;
perror("write error\n");
exit(0);
}
pos += ret;
len -= ret;
}
}
close(fd);
exit(0);
}
3.然后使用漏桶进行流量控制,让程序每秒钟cat10个字节的数据
signal + alarm + pause + 信号打断阻塞的系统调用
缺点:如果没有数据的时候 就会一直循环等待,直到有数据,如果忽然来的数据量很大,也不能快速的去读数据,只能慢慢的一秒10个字节的去读n次
funnel.c
#include
#include
#include
#include
#include
#include
#include
#include
#define SIZE 10
static int loop = 0;
static void alrm_handler(int a)
{
loop = 1;
alarm(1);
}
int main(int argc,char *argv[])
{
char *buf[SIZE];
int fd,len,pos,ret;
if(argc < 2)
{
fprintf(stderr,"Usage.....\n");
exit(0);
}
signal(SIGALRM,alrm_handler);
alarm(1);
do{
fd = open(argv[1],O_RDONLY);
if(fd < 0)
{
if(errno != EINTR)
{
perror("open error\n");
exit(0);
}
}
}while(fd < 0);
while(1)
{
//休眠挂起 直到收到信号,重新开始执行while(!loop)循环,实现一秒一输出
// 这里也可以 不用pause(),while()后 执行空,但是这样 CPU 占用率会很高,一秒钟会在这里执行循环上亿次,所以用pause()替换,直接休眠等待信号来唤醒
while(!loop)
{
pause();
}
loop = 0;
while((len = read(fd,buf,SIZE)) < 0)
{
if(errno == EINTR)
continue;
perror("read error\n");
break;
}
if(len == 0)
break;
pos = 0;
while(len > 0)
{
ret = write(1,buf,len);
if(ret < 0)
{
if(errno == EINTR)
continue;
perror("write\n");
exit(0);
}
pos += ret;
len -= ret;
}
}
exit(0);
close(fd);
}
因为漏桶有点死板,且通用性不强,因此出现了一个实用性更强且更加灵活的流量控制算法,就是令牌桶
令牌桶的优势,就是 当没有数据可读的时候,会积攒自己的权限,意思是 如果之前n秒内一直没有数据,读空了n秒,那么就存下n个权限,等到有数据的时候,快速使用前面n个权限,快速连续读n次。
#include
#include
#include
#include
#include
#include
#include
#include
#define CSP 10
#define SIZE CSP
#define TOP 100
static int token = 0;
static void alrm_handler(int a)
{
token++;
alarm(1);
if(token > TOP)
{
token = TOP;
}
}
int main(int argc,char *argv[])
{
char *buf[SIZE];
int fd,len,pos,ret;
if(argc < 2)
{
fprintf(stderr,"Usage.....\n");
exit(0);
}
signal(SIGALRM,alrm_handler);
alarm(1);
do{
fd = open(argv[1],O_RDONLY);
if(fd < 0)
{
if(errno != EINTR)
{
perror("open error\n");
exit(0);
}
}
}while(fd < 0);
while(1)
{
while(token < 0)
{
pause();
}
token--;
while((len = read(fd,buf,SIZE)) < 0)
{
if(errno == EINTR)
continue;
perror("read error\n");
break;
}
if(len == 0)
break;
pos = 0;
while(len > 0)
{
ret = write(1,buf,len);
if(ret < 0)
{
if(errno == EINTR)
continue;
perror("write\n");
exit(0);
}
pos += ret;
len -= ret;
}
}
exit(0);
}