限速
首先定义两个获取系统当前时间的函数:
static struct timeval s_curr_time;
long get_time_sec(void)
{
if (gettimeofday(&s_curr_time, NULL) < 0)
{
ERR_EXIT("gettimeofday");
}
return s_curr_time.tv_sec;
}
long get_time_usec(void)
{
return s_curr_time.tv_usec;
}
get_time_sec()函数获取系统当前时间的秒数,get_time_usec()函数获取当前系统的微妙数。这里有个little trick,将结构体设置为静态的,获取秒数的时候调用gettimeofday访问结构体,在获取微秒的时候直接访问结构体中的成员。
定义一个睡眠函数,其实内部调用的是系统函数nanosleep:
void nano_sleep(double seconds)
{
time_t secs = (time_t)seconds; // 整数部分
double fractional = seconds - (double)secs; // 小数部分
struct timespec ts;
ts.tv_sec = secs;
ts.tv_nsec = (long)(fractional * (double)1000000000);
int ret;
do
{
ret = nanosleep(&ts, &ts);
}
while (ret == -1 && errno == EINTR);//条件为真的时候,睡眠剩余的时间会保存在第二个&ts中
//返回值ret为0的时候,睡眠完成
}
time_t的类型就是long int。
限速函数;
/*
parameters: session_t会话结构体 传输的字节数 上传/下载标志位
return value:void
*/
void limit_rate(session_t *sess, int bytes_transfered, int is_upload)
{
//数据连接_空闲断开
sess->data_process = 1;
//如果配置文件中的上传/下载限速配置为0,直接返回
if(sess->bw_upload_rate_max==0 && sess->bw_download_rate_max==0)
return;
//记录当前时间
long curr_sec = get_time_sec();
long curr_usec = get_time_usec();
//计算传输count个字节的时间
double elapsed;
elapsed = (double)(curr_sec - sess->bw_transfer_start_sec);
elapsed += (double)(curr_usec - sess->bw_transfer_start_usec) / (double)1000000;
//计算当前传输速率
unsigned int bw_rate = (unsigned int)((double)bytes_transfered / elapsed);
double rate_ratio;
if(is_upload)//上传
{
if(bw_rate <= sess->bw_upload_rate_max)//速率小于限制,更新计时起点
{
sess->bw_transfer_start_sec = curr_sec;
sess->bw_transfer_start_usec = curr_usec;
return;
}
//计算速率与最大速率的比值
rate_ratio = (bw_rate / sess->bw_upload_rate_max);
}
else//下载
{
if(bw_rate <= sess->bw_download_rate_max)
{
sess->bw_transfer_start_sec = curr_sec;
sess->bw_transfer_start_usec = curr_usec;
return;
}
rate_ratio = (bw_rate / sess->bw_download_rate_max);
}
//睡眠
double pause_time = (rate_ratio - (double)1) * elapsed;
nano_sleep(pause_time);
//睡眠完,更新计时起点
sess->bw_transfer_start_sec = get_time_sec();
sess->bw_transfer_start_usec = get_time_usec();
}
将限速函数,放在上传和下载函数中,读和写的位置之间,即可实现功能。