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...\n");
        exit(1);
    }

    //2.令牌桶初始化:返回值是令牌桶的指针
    tbf = mytbf_init(CPS,BURST);
    if(tbf == NULL)
    {
        fprintf(stderr,"mytbf_init()failed !\n");
        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\n",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

 

posted @ 2016-03-22 09:17  muzihuan  阅读(1141)  评论(0编辑  收藏  举报