流量控制(漏桶和令牌桶)

由实例一步一步演化:

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);
}

你可能感兴趣的:(linux系统编程,c++,linux)