Chinaunix首页 | 论坛 | 博客
  • 博客访问: 5762003
  • 博文数量: 675
  • 博客积分: 20301
  • 博客等级: 上将
  • 技术积分: 7671
  • 用 户 组: 普通用户
  • 注册时间: 2005-12-31 16:15
文章分类

全部博文(675)

文章存档

2012年(1)

2011年(20)

2010年(14)

2009年(63)

2008年(118)

2007年(141)

2006年(318)

分类: C/C++

2009-02-19 16:22:27

项目中需要提供主机当前网络流量的信息,主要是占用的当前的网络的带宽,提供给用户以作决策。如何获得网络流量信息呢?

思路有两个:
1、libpcap,捕包进行计算
2、/proc/net/dev文件中获得

方法一,很dirty,而且需要引入libpcap库,效率不好,而且libpcap还可能丢报,统计的信息不一定准确。
方法二,/proc/net/dev文件中没有speed的信息,只有recv和trans的总量,这是内核提供的,怎么也是准确的,没有speed信息,只好自己动手丰衣足食了;-)

忽然想起一些applet有监控网络的功能,会提供传输速度的信息,例如Gnome System Monitor就可以,但是太大了,不好裁减。有一些比较小的applet,例如gkrellm和conky,都是一个类型的。翻看了两个代码,gkrellm是GTK的,conky是纯C的,当然选择conky了,search了一下,裁减了conky的一些数据结构和提取了部分代码,写了提供网络发送和接收速度信息的函数:

#ifndef _GNU_SOURCE
#define _GNU_SOURCE
#endif
#include
#include
#include
#include
#include
#include
#include
#include

#define MAX_BUFF_SIZE 256

struct net_stat {
    const char *dev;
    int up;
    long long last_read_recv, last_read_trans; //last read total num
    long long recv, trans; //real total num
    double recv_speed, trans_speed;
};

/* network interface stuff */
static struct net_stat netstats[16]={0};

struct net_stat *get_net_stat(const char *dev)
{
    unsigned int i=0;

    if (!dev) {
        return 0;
    }

    /* find interface stat */
    for (i = 0; i < 16; i++) {
        if (netstats[i].dev && strcmp(netstats[i].dev, dev) == 0) {
            return &netstats[i];
        }
    }

    /* wasn't found? add it */
    if (i == 16) {
        for (i = 0; i < 16; i++) {
            if (netstats[i].dev == 0) {
                netstats[i].dev = strndup(dev, MAX_BUFF_SIZE);
                return &netstats[i];
            }
        }
    }

    fprintf(stderr, "too many interfaces used (limit is 16)");
    return 0;
}

void clear_net_stats(void)
{
    memset(netstats, 0, sizeof(netstats));
}

void update_net_stats(const char* dev, double delta)
{
    FILE *net_dev_fp;

    // FIXME: arbitrary size chosen to keep code simple.
    int i=0;
    char buf[256]={0};

    /* open file and ignore first two lines */
    if (!(net_dev_fp = fopen("/proc/net/dev", "r"))) {
        fprintf(stderr, "fopen failed.\n");
        clear_net_stats();
        return;
    }

    fgets(buf, 255, net_dev_fp);    /* garbage */
    fgets(buf, 255, net_dev_fp);    /* garbage (field names) */

    /* read each interface */
    for (i = 0; i < 16; i++) {
        struct net_stat *ns=NULL;
        unsigned char *s=NULL, *p=NULL;
        unsigned long long r=0, t=0;
        unsigned long long last_recv=0, last_trans=0;

        if (fgets(buf, 255, net_dev_fp) == NULL) {
            //File EOF
            break;
        }

        //Skip Space
        p = buf;
        while (isspace((int) *p)) {
            p++;
        }

        /*s: network interface name*/
        s = p;

        //Skip Network Interface Name
        while (*p && *p != ':') {
            p++;
        }
        if (*p == '\0') {
            continue;
        }
        *p = '\0';

        /*p: reveive bytes*/
        p++;

        //Judge Network Interface or Not?
        if(strcmp(s, dev) != 0)
            continue;

        //Get struct net_stat
        ns = get_net_stat(s);
        ns->up = 1;

        last_recv = ns->recv;
        last_trans = ns->trans;

        /* bytes packets errs drop fifo frame compressed multicast|bytes ... */
        sscanf(p, "%lld  %*d     %*d  %*d  %*d  %*d   %*d        %*d       %lld",
            &r, &t);

        /* if recv or trans is less than last time, an overflow happened */
        if (r < ns->last_read_recv) {
            last_recv = 0;
        } else {
            ns->recv += (r - ns->last_read_recv);
        }
        ns->last_read_recv = r;

        if (t < ns->last_read_trans) {
            last_trans = 0;
        } else {
            ns->trans += (t - ns->last_read_trans);
        }
        ns->last_read_trans = t;

        /* calculate speeds */
        if(last_recv == 0)
            ns->recv_speed = 0;
        else
            ns->recv_speed = (ns->recv - last_recv) / delta;

        if(last_trans == 0)
            ns->trans_speed = 0;
        else
            ns->trans_speed = (ns->trans - last_trans) / delta;

        /*
        //First Time Run, Or Time Overflow
        if(current_time == 0)
        {
            ns->recv_speed = 0;
            ns->trans_speed = 0;
        }
        */
        //Find Network Interface, And Work Over
        break;
    }

    fclose(net_dev_fp);
}

int main()
{
    int i=0;
    unsigned int sleep_time = 0;
    struct net_stat* ns = NULL;
    time_t current_time=0, last_time=0, delta_time=0;

    srand(time(NULL));
    for(i=0; i<10000; i++)
    {
    
        last_time = current_time;
        current_time = time(NULL);
        delta_time = current_time-last_time;
        printf("Delta Time: %u Seconds\n", delta_time);

        update_net_stats("eth0", delta_time);
        ns = get_net_stat("eth0");

        printf("Recv Speed: %f KB/s\n", ns->recv_speed/1024);
        printf("Send Speed: %f KB/s\n", ns->trans_speed/1024);

        sleep_time = 1+random()%5;
        printf("Sleep %d Second...\n", sleep_time);
        sleep(sleep_time);
    }

    return 0;
}

阅读(2289) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~