zoukankan      html  css  js  c++  java
  • linux高编信号-------令牌桶实现

    main.c

    /*********************************
     *功能:每秒从文件读N个字节(N可控)
     *使用信号机制实现令牌桶:解决数据流不均匀传输
     * *****************************/
    
    #include <stdio.h>
    #include <stdlib.h>
    #include <sys/types.h>
    #include <sys/stat.h>
    #include <fcntl.h>
    #include <errno.h>
    #include <signal.h>
    #include <string.h>
    #include "mytbf.h"
    
    /*一次读写10个字符*/
    #define CPS     10
    #define BUFSIZE 1024
    #define BURST   100//100次权限
    
    int main(int argc ,char **argv)
    {
        int sfd ,dfd = 1 ;
        char buf[BUFSIZE];
        int len ,ret , pos ;
        mytbf_t *tbf ;
        int size ;
        //1.判断输入参数
        if(argc < 2)
        {
            fprintf(stderr , "Usage...
    ");
            exit(1);
        }
    
        //2.令牌桶初始化:返回值是令牌桶的指针
        tbf = mytbf_init(CPS,BURST);
        if(tbf == NULL)
        {
            fprintf(stderr,"mytbf_init()failed !
    ");
            exit(1);
        }
    
        //3.打开文件
        do
        {
            //3.1打开文件
            sfd = open(argv[1],O_RDONLY);
            if(sfd < 0 )
            {
                if(errno != EINTR)//判断不是被信号打断的错误情况
                {
                    perror("open()");
                    exit(1);
                }
            }
        }while(sfd < 0);
    
        //4.读文件(有令牌就可以读出来)
        while(1)
        {
            //4.1从令牌桶取令牌
            size = mytbf_fetchtoken(tbf ,BUFSIZE);
            if(size < 0 )
            {
                fprintf(stderr , "mytbf_fetchtoken():%s
    ",strerror(-size));
                exit(1);
            }
            //4.2读数据
            while((len = read(sfd,buf,size)) < 0 )
            {
                if(errno == EINTR)
                    continue ;
                perror("read()");
                exit(1);
            }
            if(len ==0)
                break;
            //4.3如果读出来的字符小于令牌的数量需要归还令牌
            if(size - len > 0)
                mytbf_returntoken(tbf,size-len);
            pos = 0;
    
            //5.写数据
            while(len > 0)
            {
                ret = write(dfd , buf+pos, len);
                if(ret < 0)
                {
                    if(errno == EINTR)
                        continue ;
                    perror("write()");
                    exit(1);
                }
                pos+=ret ;
                len -=ret ;
            }
            sleep(1);
        }
        //6.关闭文件并且销毁当前令牌桶
        mytbf_destroy(tbf);
        close(sfd);
        exit(0);
    }

    mytbf.c

    #include <stdio.h>
    #include <stdlib.h>
    #include <signal.h>
    #include "mytbf.h"
    #include <errno.h>
    
    typedef void(*sighandler_t)(int );
    
    //令牌桶数组:存在令牌的地址
    static struct mytbf_st* job[MYTBF_MAX];
    
    //信号初始状态
    static int inited  = 0 ;
    
    static sighandler_t alrm_handler_save ;
    
    /*****令牌桶信息控制结构体****/
    struct mytbf_st
    {
        int cps ;//每秒速率
        int burst ;//最大保存令牌数量
        int token ;//令牌数量
        int pos ;//令牌桶的位置
    };
    
    /****************************
     *功能:令牌桶数组里面找空位
     *返回值:大于等于0空位下标;-1没有空位
     * **************************/
    static int get_free_pos(void)
    {
        int i ;
        for(i = 0 ; i < MYTBF_MAX ;i++)
        {
            if(job[i]==NULL)
                return i;
        }
        return -1 ;
    }
    
    /**********信号处理函数*********/
    static void alrm_handler(int s)
    {
        int i ;
        //1.启动下次信号中断
        alarm(1);
    
        for(i = 0 ; i  < MYTBF_MAX ; i++)
        {
            if(job[i] !=NULL)
            {
                job[i]->token+=job[i]->cps ;
                if(job[i]->token > job[i]->burst)
                    job[i]->token = job[i]->burst ;
            }
        }
    }
    
    /******比较大小********/
    static int min(int a,int b)
    {
        if(a < b)
            return a ;
        return b ;
    }
    
    /********卸载模块**********/
    static void module_unload(void)
    {
        int i ;
        signal(SIGALRM,alrm_handler_save);
        alarm(0);
        for(i = 0 ; i < MYTBF_MAX ;i++)
            free(job[i]);
    }
    
    /**********加载模块************/
    static void module_load(void)
    {
        alrm_handler_save = signal(SIGALRM,alrm_handler);
        alarm(1);
        atexit(module_unload);
    }
    /*******************************
     *功能:创建令牌桶
     *参数:cps:每秒读多少个字符个数
     *      burst:上限
     *返回值:结构体的起始位置指针
     * ****************************/
    mytbf_t *mytbf_init(int cps , int burst)
    {
        struct mytbf_st *me ;
        int pos ;
        //1.第一次启动
        if(inited == 0)
        {
            module_load();
            inited = 1 ;
    
        }
        //2.找令牌桶数组的空位下标
        pos = get_free_pos();
        if(pos < 0)
            return NULL ;
    
        //3.初始化
        me = malloc(sizeof(*me));
        if(me == NULL)
            return NULL;
        me->token = 0 ;
        me->burst = burst ;
        me->cps = cps ;
        me->pos = pos ;
        //4.将
        job[pos] = me ;
        return me ;
    }
    
    /*******************************
     *功能:获取令牌
     *参数:ptr:令牌桶地址
     *      size:获取多少个令牌
     *返回值:成功返回令牌数
     * ****************************/
    int mytbf_fetchtoken(mytbf_t *ptr ,int size )
    {
        int n;
        struct mytbf_st *me = ptr ;
        if(size <= 0)
            return -EINVAL ;
    
        while(me->token <= 0)
            pause();
        n = min(me->token,size);
        me->token -=n ;
        return n ;
    }
    
    
    /*******************************
     *功能:归还令牌
     *参数:ptr:令牌桶地址
     *      size:归还令牌数量
     *返回值:结构体的起始位置指针
     * ****************************/
    int mytbf_returntoken(mytbf_t * ptr,int size )
    {
        struct mytbf_st *me = ptr ;
        if(size <=0)
            return -EINVAL ;
        me->token +=size ;
        if(me->token > me->burst )
            me->token = me->burst ;
        return size ;
    }
    
    /*******************************
     *功能:删除令牌桶
     *参数:ptr:删除的令牌桶地址
     *返回值:无
     * ****************************/
    
    void mytbf_destroy(mytbf_t *ptr)
    {
        struct mytbf_st *me = ptr ;
        job[me->pos] = NULL ;
        free(ptr);
    }

    mytbf.h

    #ifndef MYTBF_H__
    #define MYTBF_H__
    
    #define MYTBF_MAX   1024//令牌桶的最大数量
    
    typedef void mytbf_t ;
    
    int mytbf_fetchtoken(mytbf_t * ,int );
    
    int mytbf_returntoken(mytbf_t * ,int );
    
    int mytbf_destroy(mytbf_t *);
    #endif

    Makefile

    all:mytbf
    mytbf:main.o mytbf.o
        gcc $^ -o $@
    clean:
        rm -rf *.o mytbf
  • 相关阅读:
    Spring Boot全日志设置
    SpringBoot整合Quartz
    Kubernetes网络方案的三大类别和六个场景
    微服务化之缓存的设计
    金融创新业务基于容器云的微服务化实践
    致传统企业朋友:不够痛就别微服务,有坑 (1)
    致传统企业朋友:不够痛就别微服务,有坑 (2)
    The Beam Model:Stream & Tables翻译(上)
    细说Mammut大数据系统测试环境Docker迁移之路
    [译] 关于 SPA,你需要掌握的 4 层 (1)
  • 原文地址:https://www.cnblogs.com/muzihuan/p/5304757.html
Copyright © 2011-2022 走看看