linux高编信号-------令牌桶实现

摘要:
“);exit;}//3.打开文件do{//3.1打开文件sfd=Open;if{if(errno!

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

免责声明:文章转载自《linux高编信号-------令牌桶实现》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇P2P系统,一致性哈希和DHT分布式系统详解--基础知识(概论)下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

linux Boot目录满了之后的解决方法

boot目录为什么会满? Linux默认分区时,boot分区就200多M,按理说也不小,足够了(实际也就几十M),但是内核经常性的升级,而且自己又不自动卸载,于是该目录下旧的内核文件越积越多,最后就满了。 解决方法: 删除多余的内核文件 步骤: (1)输入 uname -a 获取当前正在使用内核    (2) 输入 dpkg --get-selectio...

cmake 备忘录

记录使用 cmake 时的常见需求和解决办法。 目录 1. 用于执行CMake的.bat脚本 2. 判断平台:32位还是64位? 3. 判断Visual Studio版本 4. 判断操作系统 5. 判断是Debug还是Release等版本 6. 根据Debug/Release添加不同的库目录 7. Visual Studio属性与对应CMake实现方法...

【web端权限维持】利用ADS隐藏webshell

0X01 前言   未知攻,焉知防,在web端如何做手脚维护自己拿到的权限呢?首先要面临的是webshell查杀,那么通过利用ADS隐藏webshell,不失为一个好办法。 0X02 利用ADS隐藏webshell   关于ADS的介绍,就不再阐述,详见尾部参考资料。   PHP 一句话木马:<?php @eval($_POST['chopper']...

临时解决linux下time wait问题

 通过 netstat  -anp | grepTIME_WAIT | wc -l 命令查看数量,发现TIME_WAIT的连接数量超过了阈值   1、初步怀疑是程序没有关闭连接,codereview了两遍,发现,已经正常关闭。 2、网上看TIME_WAIT产生的原因,可能是因为服务器主动关闭连接导致TIME_WAIT产生。 3、查找TIME_WAIT解决...

linux 安装 Samba服务

 Samba Samba是在Linux和UNIX系统上实现SMB协议的一个免费软件,由服务器及客户端程序构成。SMB(Server Messages Block,信息服务块)是一种在局域网上共享文件和打印机的一种通信协议,它为局域网内的不同计算机之间提供文件及打印机等资源的共享服务。SMB协议是客户机/服务器型协议,客户机通过该协议可以访问服务器上的共享文...

C++实现01串排序

题目内容:将01串首先按长度排序,长度相同时,按1的个数从少到多进行排序,1的个数相同时再按ASCII码值排序。 输入描述:输入数据中含有一些01串,01串的长度不大于256个字符。 输出描述:重新排列01串的顺序,使得串按题目描述的方式排序。 题目分析: (1)定义一个多重集合容器,该容器的元素类型为string,采用设定的比较函数 (2)因为元素是st...