本代码使用的是ifstat-1.1版本,在此基础上进行了简化修改,直接获取当前设备所有网卡的信息。代码已经没有了源码的模样,已经被修改的面目全非,仅仅是通过代码了解一下获取网络流量的方法。基本方法是通过两次读取/proc/net/dev(ifstat网络流量监控之/proc/net/dev文件)文件计算时间差来计算IO流量。
扫描设备的网卡用到了if_nameindex()系列函数,代码中给出了详细的注释。同时还可以上网去了解更详细的信息。
#include <unistd.h>
#include <string.h>
#include <time.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/ioctl.h>
#include <net/if.h>
#include <errno.h>
#define PROC_FILE_PATH "/proc/net/dev"
/* interface flags */
#define IFSTAT_LOOPBACK 1
#define IFSTAT_DOWN 2
#define IFSTAT_HASSTATS 4
#define IFSTAT_HASINDEX 8
#define IFSTAT_TOTAL 128
/*网卡列表*/
struct ifstat_data
{
char *name;
int namelen;
unsigned long obout, obin, bout, bin;
int flags;
struct ifstat_data *next;
};
struct ifstat_list
{
struct ifstat_data *first;
int flags;
};
/*设备数据*/
struct ifstat_driver
{
char *name;
/*驱动设备初始化,成功返回1*/
int (*open_driver) (struct ifstat_driver *driver);
/*扫描设备列表*/
int (*scan_interfaces) (struct ifstat_driver *driver,struct ifstat_list *ifs);
/*收集信息,并更新列表*/
int (*get_stats) (struct ifstat_driver *driver,struct ifstat_list *ifs);
/*关闭设备数据获取*/
void (*close_driver) (struct ifstat_driver *driver);
/*私有数据*/
void *data;
};
struct proc_driver_data
{
char *file;
int checked;
};
//重置标志信息
void ifstat_reset_interfaces(struct ifstat_list *ifs)
{
struct ifstat_data *ptr;
int hasindex = 1;
for (ptr = ifs->first; ptr != NULL; ptr = ptr->next)
{
if (!(ptr->flags & IFSTAT_HASINDEX))
hasindex = 0;
ptr->flags &= ~(IFSTAT_HASSTATS|IFSTAT_HASINDEX);
}
if (hasindex)
ifs->flags |= IFSTAT_HASINDEX;
else
ifs->flags &= ~IFSTAT_HASINDEX;
}
void ifstat_add_interface(struct ifstat_list *ifs, char *ifname, int flags)
{
struct ifstat_data *cur, *last;
int len;
/*检查网卡名称*/
if (*ifname == '\0')
return;
len = strlen(ifname);
last = NULL;
for (cur = ifs->first; cur != NULL; cur = cur->next)
{
if (len == cur->namelen && cur->name[0] == ifname[0] &&
!strncmp(cur->name + 1, ifname + 1, len - 1) &&
!(flags & IFSTAT_TOTAL) && !(cur->flags & IFSTAT_TOTAL))
return;
last = cur;
}
if ((cur = calloc(1, sizeof(struct ifstat_data))) == NULL)
{
printf("[%s %d]malloc error\n",__FUNCTION__,__LINE__);
exit(EXIT_FAILURE);
}
cur->name = strdup(ifname);
cur->namelen = len;
cur->flags = flags;
if (last != NULL)
last->next = cur;
if (ifs->first == NULL)
ifs->first = cur;
}
void ifstat_free_interface(struct ifstat_data *data)
{
free(data->name);
free(data);
}
struct ifstat_data *ifstat_get_interface(struct ifstat_list *ifs, char *ifname)
{
struct ifstat_data *ptr;
int len = strlen(ifname);
for (ptr = ifs->first; ptr != NULL; ptr = ptr->next)
{
if (len == ptr->namelen && ptr->name[0] == ifname[0] &&
!strncmp(ptr->name + 1, ifname + 1, len - 1) &&
!(ptr->flags & IFSTAT_TOTAL))
{
return ptr;
}
}
return NULL;
}
void ifstat_set_interface_stats(struct ifstat_data *data,
unsigned long bytesin,
unsigned long bytesout)
{
if (data->bout > bytesout || data->bin > bytesin)
{
printf("[%s %d]warning: rollover for interface %s, reinitialising\n",__FUNCTION__,__LINE__, data->name);
data->obout = bytesout;
data->obin = bytesin;
}
else
{
data->obout = data->bout;
data->obin = data->bin;
}
data->bout = bytesout;
data->bin = bytesin;
data->flags |= IFSTAT_HASSTATS;
}
static void examine_interface(struct ifstat_list *ifs, char *name,int ifflags)
{
if ((ifflags & IFF_LOOPBACK) && !(ifs->flags & IFSTAT_LOOPBACK))
return;
if (!(ifflags & IFF_UP) && !(ifs->flags & IFSTAT_DOWN))
return;
ifstat_add_interface(ifs, name, 0);
}
static int ioctl_map_ifs(int sd,int (*mapf)(int sd, struct ifreq *ifr, void *data),void *mdata)
{
/*******************************************函数调用说明*************************************************
if_nametoindex():指定网络接口名称字符串作为参数;
若该接口存在,则返回相应的索引,
否则返回0
if_indextoname():指定网络接口索引以及一块长度至少为IF_NAMESIZE(16)字节的内存区域作为参数;
若索引对应的网络接口存在,则在内存区域中返回该接口的名称字符串,
否则返回NULL,并将errno设置为相应的值
if_nameindex():返回动态分配的struct if_nameindex结构数组,数组中的每一个元素分别对应一个本地网络接口;
struct if_nameindex结构的if_index字段为接口索引,if_name字段为接口名称字符串;
索引为0且名称字符串为NULL表示结构数组的末尾;
调用出错时,返回NULL,并将errno设置为相应的值
if_freenameindex():通过if_nameindex()获取完毕接口名称与索引后,调用该函数以释放动态分配的内存区域。
以上4个函数在系统的man文档中都可以查看相应的描述,且都是POSIX标准支持的,Linux内核可能未实现这些函数,
或已实现但不同于POSIX标准。这些函数的原型声明与定义并未出现在CentOS 6.7的定制内核2.6.32-573.26.1.el6.x86_64
以及原版内核2.6.32.5中,而是由系统的glibc-2.12实现:在glibc-2.12.2源码树中,
函数的原型声明位于sysdeps/gnu/net/if.h与sysdeps/generic/net/if.h,
函数的定义位于sysdeps/unix/sysv/linux/if_index.c中,
本质上是对ioctl(2)的SIOCGIFNAME,SIOCGIFCONF,SIOCGIFINDEX等操作以及netlink套接字进行了封装
************************************************************************************************************/
struct if_nameindex *iflist, *cur;
struct ifreq ifr;
if ((iflist = if_nameindex()) == NULL)
{
printf("[%s %d]if_nameindex error\n",__FUNCTION__,__LINE__);
return 0;
}
for(cur = iflist; cur->if_index != 0 && cur->if_name != NULL; cur++)
{
memcpy(ifr.ifr_name, cur->if_name, sizeof(ifr.ifr_name));
ifr.ifr_name[sizeof(ifr.ifr_name) - 1] = '\0';
if (!mapf(sd, &ifr, mdata))
return 0;
}
if_freenameindex(iflist);
return 1;
}
static int ioctl_map_scan(int sd, struct ifreq *ifr, void *data)
{
if (ioctl(sd, SIOCGIFFLAGS, (char *)ifr) != 0)
return 1;
examine_interface((struct ifstat_list *) data, ifr->ifr_name,ifr->ifr_flags);
return 1;
}
static int ioctl_scan_interfaces(struct ifstat_driver *driver,struct ifstat_list *ifs)
{
int sd;
if ((sd = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
{
printf("[%s %d]socket error\n",__FUNCTION__,__LINE__);
return 0;
}
ioctl_map_ifs(sd, &ioctl_map_scan, (void *) ifs);
close(sd);
return 1;
}
static int proc_open_driver(struct ifstat_driver *driver)
{
struct proc_driver_data *data;
if ((data = malloc(sizeof(struct proc_driver_data))) == NULL)
{
printf("[%s %d]malloc error\n",__FUNCTION__,__LINE__);
return 0;
}
data->file = NULL;
data->checked = 0;
driver->data = (void *) data;
return 1;
}
static void proc_close_driver(struct ifstat_driver *driver)
{
struct proc_driver_data *data = driver->data;
if (data->file != NULL)
free(data->file);
free(data);
}
static int proc_get_stats(struct ifstat_driver *driver,struct ifstat_list *ifs)
{
char buf[1024];
FILE *f;
char *iface, *stats;
unsigned long bytesin, bytesout;
struct ifstat_data *cur;
struct proc_driver_data *data = driver->data;
char *file;
if (data->file != NULL)
file = data->file;
else
file = PROC_FILE_PATH;
if ((f = fopen(file, "r")) == NULL)
{
printf("[%s %d]can't open %s: %s\n",__FUNCTION__,__LINE__, file, strerror(errno));
return 0;
}
/*检查首行*/
if (fgets(buf, sizeof(buf), f) == NULL)
goto badproc;
if (!data->checked && strncmp(buf, "Inter-|", 7))
goto badproc;
if (fgets(buf, sizeof(buf), f) == NULL)
goto badproc;
if (!data->checked)
{
if (strncmp(buf, " face |by", 9))
goto badproc;
data->checked = 1;
}
while (fgets(buf, sizeof(buf), f) != NULL)
{
if ((stats = strchr(buf, ':')) == NULL)
continue;
*stats++ = '\0';
iface = buf;
while (*iface == ' ')
iface++;
if (*iface == '\0')
continue;
if (sscanf(stats, "%lu %*u %*u %*u %*u %*u %*u %*u %lu %*u", &bytesin, &bytesout) != 2)
continue;
if ((cur = ifstat_get_interface(ifs, iface)) != NULL)
ifstat_set_interface_stats(cur, bytesin, bytesout);
}
fclose(f);
return 1;
badproc:
fclose(f);
printf("[%s %d]%s: unsupported format\n",__FUNCTION__,__LINE__, file);
return 0;
}
int ifstat_get_driver(struct ifstat_driver *driver)
{
static struct ifstat_driver drivers[] =
{
{
"proc",
&proc_open_driver,
&ioctl_scan_interfaces,
&proc_get_stats,
&proc_close_driver
},
{NULL}
};
if (drivers[0].name == NULL)
return 0;
memcpy(driver, &(drivers[0]), sizeof(struct ifstat_driver));
driver->data = NULL;
return 1;
}
/*
eth0 lo
KB/s in KB/s out KB/s in KB/s out
14562.23 12345.25 0.00 0.00
*/
static void print_stats(struct ifstat_list *ifs,struct timeval *start,struct timeval *end)
{
struct ifstat_data *ptr;
int hasindex = 1;
double delay, kbin, kbout, tkbin, tkbout, scale;
delay = end->tv_sec - start->tv_sec + ((double) (end->tv_usec - start->tv_usec))/ (double) 1000000;
scale = delay * 1024;
tkbin = tkbout = 0;
for (ptr = ifs->first; ptr != NULL; ptr = ptr->next)
{
if (ptr->flags & IFSTAT_HASSTATS)
{
kbin = (double) (ptr->bin - ptr->obin) / (double) scale;
tkbin += kbin;
kbout = (double) (ptr->bout - ptr->obout) / (double) scale;
tkbout += kbout;
ptr->flags &= ~IFSTAT_HASSTATS;
}
else if (ptr->flags & IFSTAT_TOTAL)
{
kbin = tkbin;
kbout = tkbout;
}
else
{
kbin = -1;
kbout = -1;
}
if (ptr->flags & IFSTAT_HASINDEX)
ptr->flags &= ~IFSTAT_HASINDEX;
else
hasindex = 0;
if (kbin < 0)
kbin = 0;
if (kbout < 0)
kbout = 0;
printf("name:%s\tkbin:%0.2lfKB\tkout:%0.2lfKB\n",ptr->name,kbin,kbout);
}
if (hasindex)
ifs->flags |= IFSTAT_HASINDEX;
else
ifs->flags &= ~IFSTAT_HASINDEX;
}
static void filter_interfaces(struct ifstat_list *ifs)
{
struct ifstat_data *cur, *next, *parent;
cur = ifs->first;
parent = NULL;
while (cur != NULL)
{
if (!(cur->flags & IFSTAT_HASSTATS))
{
next = cur->next;
if (parent != NULL)
parent->next = next;
else
ifs->first = next;
ifstat_free_interface(cur);
cur = next;
}
else
{
parent = cur;
cur = cur->next;
}
}
}
int main(int argc, char **argv)
{
struct ifstat_list ifs;
struct ifstat_driver driver;
struct timeval start, tv_delay, tv;
ifs.flags = 0;
ifs.first = NULL;
/*映射接口*/
if (!ifstat_get_driver(&driver))
{
return EXIT_FAILURE;
}
/*初始化网卡设备*/
if (driver.open_driver != NULL &&!driver.open_driver(&driver))
return EXIT_FAILURE;
if (ifs.first == NULL)
driver.scan_interfaces(&driver, &ifs);
/*第一次查询网卡数据*/
if (ifs.first != NULL)
{
if (driver.get_stats != NULL && !driver.get_stats(&driver, &ifs))
return EXIT_FAILURE;
gettimeofday(&start, NULL);//获取当前时间
filter_interfaces(&ifs);
ifstat_reset_interfaces(&ifs);
}
if (ifs.first == NULL)
{
if (driver.close_driver != NULL)
driver.close_driver(&driver);
return EXIT_FAILURE;
}
if (ifs.flags & IFSTAT_TOTAL)
{
ifstat_add_interface(&ifs, "Total", IFSTAT_TOTAL);
}
tv_delay.tv_sec = 1;
tv_delay.tv_usec = (int) ((1 - tv_delay.tv_sec) * 1000000);
while(1)
{
printf("\n###############################################\n");
tv = tv_delay;
select(0, NULL, NULL, NULL, &tv);
if (driver.get_stats != NULL && !driver.get_stats(&driver, &ifs))
return EXIT_FAILURE;
gettimeofday(&tv, NULL);
print_stats(&ifs, &start, &tv);
start = tv;
fflush(stdout);
}
if (driver.close_driver != NULL)
driver.close_driver(&driver);
return EXIT_SUCCESS;
}
代码中涉及到的函数如图所示:
程序运行结果如图所示:
###############################################
name:ens2f0 kbin:402.55Kb kout:6.43Kb
name:ens2f1 kbin:748.04Kb kout:6.37Kb
name:ens3f0 kbin:0.00Kb kout:0.00Kb
name:enp4s0f0 kbin:414.43Kb kout:6.59Kb
name:enp4s0f1 kbin:518.85Kb kout:6.46Kb
name:ens3f1 kbin:0.00Kb kout:0.00Kb
name:bond0 kbin:2083.87Kb kout:25.86Kb
###############################################
name:ens2f0 kbin:536.68Kb kout:5.01Kb
name:ens2f1 kbin:395.57Kb kout:5.36Kb
name:ens3f0 kbin:0.00Kb kout:0.00Kb
name:enp4s0f0 kbin:583.30Kb kout:5.08Kb
name:enp4s0f1 kbin:162.78Kb kout:5.15Kb
name:ens3f1 kbin:0.00Kb kout:0.00Kb
name:bond0 kbin:1678.33Kb kout:20.60Kb
###############################################
name:ens2f0 kbin:334.01Kb kout:5.66Kb
name:ens2f1 kbin:664.27Kb kout:5.88Kb
name:ens3f0 kbin:0.00Kb kout:0.00Kb
name:enp4s0f0 kbin:569.79Kb kout:5.62Kb
name:enp4s0f1 kbin:464.94Kb kout:5.63Kb
name:ens3f1 kbin:0.00Kb kout:0.00Kb
name:bond0 kbin:2033.00Kb kout:22.79Kb
###############################################
name:ens2f0 kbin:237.78Kb kout:5.46Kb
name:ens2f1 kbin:459.81Kb kout:5.27Kb
name:ens3f0 kbin:0.00Kb kout:0.00Kb
name:enp4s0f0 kbin:605.53Kb kout:5.15Kb
name:enp4s0f1 kbin:403.94Kb kout:5.35Kb
name:ens3f1 kbin:0.00Kb kout:0.00Kb
name:bond0 kbin:1714.43Kb kout:21.23Kb
###############################################
name:ens2f0 kbin:432.40Kb kout:5.66Kb
name:ens2f1 kbin:497.88Kb kout:5.91Kb
name:ens3f0 kbin:0.00Kb kout:0.00Kb
name:enp4s0f0 kbin:706.00Kb kout:6.12Kb
name:enp4s0f1 kbin:409.88Kb kout:6.02Kb
name:ens3f1 kbin:0.00Kb kout:0.00Kb
name:bond0 kbin:2038.79Kb kout:23.71Kb
简化一下代码,对于/proc/net/dev文件的读取以及对网络流量数据的监控理解起来会更简洁。
#include <unistd.h>
#include <string.h>
#include <time.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/ioctl.h>
#include <net/if.h>
#include <errno.h>
#define PROC_FILE_PATH "/proc/net/dev"
/*网卡列表*/
struct ifstat_data
{
char *name;
int namelen;
unsigned long obout, obin, bout, bin;
struct ifstat_data *next;
};
struct ifstat_data *ifstat_get_interface(struct ifstat_data *ifs, char *ifname)
{
struct ifstat_data *ptr;
int len = strlen(ifname);
for (ptr = ifs; ptr != NULL; ptr = ptr->next)
{
if (len == ptr->namelen && ptr->name[0] == ifname[0] &&
!strncmp(ptr->name + 1, ifname + 1, len - 1))
{
return ptr;
}
}
return NULL;
}
void ifstat_set_interface_stats(struct ifstat_data *data,
unsigned long bytesin,
unsigned long bytesout)
{
if (data->bout > bytesout || data->bin > bytesin)
{
printf("[%s %d]warning: rollover for interface %s, reinitialising\n",__FUNCTION__,__LINE__, data->name);
data->obout = bytesout;
data->obin = bytesin;
}
else
{
data->obout = data->bout;
data->obin = data->bin;
}
data->bout = bytesout;
data->bin = bytesin;
}
static int ioctl_map_scan(int sd, struct ifreq *ifr, struct ifstat_data **ifs)
{
if (ioctl(sd, SIOCGIFFLAGS, (char *)ifr) != 0)
return 1;
if ((ifr->ifr_flags & IFF_LOOPBACK))
return 1;
if (!(ifr->ifr_flags & IFF_UP))
return 1;
struct ifstat_data *cur, *last = NULL;
/*检查网卡名称*/
if (*ifr->ifr_name == '\0')
return 1;
int len = strlen(ifr->ifr_name);
for (cur = *ifs; cur != NULL; cur = cur->next)
{
if (len == cur->namelen && cur->name[0] == ifr->ifr_name[0] &&
!strncmp(cur->name + 1, ifr->ifr_name + 1, len - 1))
return 1;
last = cur;
}
if ((cur = calloc(1, sizeof(struct ifstat_data))) == NULL)
{
printf("[%s %d]malloc error\n",__FUNCTION__,__LINE__);
exit(EXIT_FAILURE);
}
cur->name = strdup(ifr->ifr_name);
cur->namelen = len;
if (last != NULL)
last->next = cur;
if (*ifs == NULL)
*ifs = cur;
return 1;
}
static int ioctl_scan_interfaces(struct ifstat_data **ifs)
{
int sd;
struct ifstat_data *ifs_temp = NULL;
if ((sd = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
{
printf("[%s %d]socket error\n",__FUNCTION__,__LINE__);
return 0;
}
//ioctl_map_ifs(sd, &ioctl_map_scan, (void *) ifs);
/*******************************************函数调用说明*************************************************
if_nametoindex():指定网络接口名称字符串作为参数;
若该接口存在,则返回相应的索引,
否则返回0
if_indextoname():指定网络接口索引以及一块长度至少为IF_NAMESIZE(16)字节的内存区域作为参数;
若索引对应的网络接口存在,则在内存区域中返回该接口的名称字符串,
否则返回NULL,并将errno设置为相应的值
if_nameindex():返回动态分配的struct if_nameindex结构数组,数组中的每一个元素分别对应一个本地网络接口;
struct if_nameindex结构的if_index字段为接口索引,if_name字段为接口名称字符串;
索引为0且名称字符串为NULL表示结构数组的末尾;
调用出错时,返回NULL,并将errno设置为相应的值
if_freenameindex():通过if_nameindex()获取完毕接口名称与索引后,调用该函数以释放动态分配的内存区域。
以上4个函数在系统的man文档中都可以查看相应的描述,且都是POSIX标准支持的,Linux内核可能未实现这些函数,
或已实现但不同于POSIX标准。这些函数的原型声明与定义并未出现在CentOS 6.7的定制内核2.6.32-573.26.1.el6.x86_64
以及原版内核2.6.32.5中,而是由系统的glibc-2.12实现:在glibc-2.12.2源码树中,
函数的原型声明位于sysdeps/gnu/net/if.h与sysdeps/generic/net/if.h,
函数的定义位于sysdeps/unix/sysv/linux/if_index.c中,
本质上是对ioctl(2)的SIOCGIFNAME,SIOCGIFCONF,SIOCGIFINDEX等操作以及netlink套接字进行了封装
************************************************************************************************************/
struct if_nameindex *iflist, *cur;
struct ifreq ifr;
if ((iflist = if_nameindex()) == NULL)
{
printf("[%s %d]if_nameindex error\n",__FUNCTION__,__LINE__);
return 0;
}
for(cur = iflist; cur->if_index != 0 && cur->if_name != NULL; cur++)
{
memcpy(ifr.ifr_name, cur->if_name, sizeof(ifr.ifr_name));
ifr.ifr_name[sizeof(ifr.ifr_name) - 1] = '\0';
if (!ioctl_map_scan(sd, &ifr, &ifs_temp))
return 0;
*ifs = ifs_temp;
}
if_freenameindex(iflist);
close(sd);
return 1;
}
static int proc_get_stats(int *checked,struct ifstat_data *ifs)
{
char buf[1024];
FILE *f;
char *iface, *stats;
unsigned long bytesin, bytesout;
struct ifstat_data *cur;
if ((f = fopen(PROC_FILE_PATH, "r")) == NULL)
{
printf("[%s %d]can't open %s: %s\n",__FUNCTION__,__LINE__, PROC_FILE_PATH, strerror(errno));
return 0;
}
/*检查首行*/
if (fgets(buf, sizeof(buf), f) == NULL)
goto badproc;
if (!*checked && strncmp(buf, "Inter-|", 7))
goto badproc;
if (fgets(buf, sizeof(buf), f) == NULL)
goto badproc;
if (!*checked)
{
if (strncmp(buf, " face |by", 9))
goto badproc;
*checked = 1;
}
while (fgets(buf, sizeof(buf), f) != NULL)
{
if ((stats = strchr(buf, ':')) == NULL)
continue;
*stats++ = '\0';
iface = buf;
while (*iface == ' ')
iface++;
if (*iface == '\0')
continue;
if (sscanf(stats, "%lu %*u %*u %*u %*u %*u %*u %*u %lu %*u", &bytesin, &bytesout) != 2)
continue;
if ((cur = ifstat_get_interface(ifs, iface)) != NULL)
ifstat_set_interface_stats(cur, bytesin, bytesout);
}
fclose(f);
return 1;
badproc:
fclose(f);
printf("[%s %d]%s: unsupported format\n",__FUNCTION__,__LINE__, PROC_FILE_PATH);
return 0;
}
static void print_stats(struct ifstat_data *ifs,struct timeval *start,struct timeval *end)
{
struct ifstat_data *ptr;
double delay, kbin, kbout;
delay = (end->tv_sec - start->tv_sec + ((double) (end->tv_usec - start->tv_usec))/ (double) 1000000)*1024;
for (ptr = ifs; ptr != NULL; ptr = ptr->next)
{
kbin = (double) (ptr->bin - ptr->obin) / (double) delay;
kbout = (double) (ptr->bout - ptr->obout) / (double) delay;
if (kbin < 0)
kbin = 0;
if (kbout < 0)
kbout = 0;
printf("name:%s\tkbin:%0.2lfKB\tkout:%0.2lfKB\n",ptr->name,kbin,kbout);
}
}
int main(int argc, char **argv)
{
struct ifstat_data *ifs = NULL;
int checked = 0;
struct timeval start, tv_delay, tv;
ioctl_scan_interfaces(&ifs);
/*第一次查询网卡数据*/
if (ifs != NULL)
{
if (!proc_get_stats(&checked,ifs))
return -1;
gettimeofday(&start, NULL);//获取当前时间
}else
return -1;
tv_delay.tv_sec = 1;
tv_delay.tv_usec = (int) ((1 - tv_delay.tv_sec) * 1000000);
while(1)
{
printf("\n###############################################\n");
tv = tv_delay;
select(0, NULL, NULL, NULL, &tv);
if (!proc_get_stats(&checked,ifs))
return -1;
gettimeofday(&tv, NULL);
print_stats(ifs, &start, &tv);
start = tv;
fflush(stdout);
}
return 0;
}