zoukankan      html  css  js  c++  java
  • 【Linux环境编程】获取网卡的实时网速

    在windows以下。我们能够看到360或者是qq安全卫士的“安全球”。上面显示实时的网速情况。那么在linux里面怎样获取网卡的实时网速?事实上原理非常easy,读取须要获取网速的网卡在某段时间dT内流量的变化dL,那么实时网速就出来了,Speed = dL / dt。

    linux在ifaddrs.h中提供了函数:

    /* Create a linked list of `struct ifaddrs' structures, one for each
       network interface on the host machine.  If successful, store the
       list in *IFAP and return 0.  On errors, return -1 and set `errno'.
                
       The storage returned in *IFAP is allocated dynamically and can
       only be properly freed by passing it to `freeifaddrs'.  */
    extern int getifaddrs (struct ifaddrs **__ifap) __THROW;
               
    /* Reclaim the storage allocated by a previous `getifaddrs' call.  */
    extern void freeifaddrs (struct ifaddrs *__ifa)  __THROW;

    系统会创建一个包括本机全部网卡信息链表,然后我们就能够在这个链表里面获取我们想要的信息。

    /* The `getifaddrs' function generates a linked list of these structures.
       Each element of the list describes one network interface.  */
    struct ifaddrs
    {
      struct ifaddrs *ifa_next; /* Pointer to the next structure.  */
    
      char *ifa_name;       /* Name of this network interface.  */
      unsigned int ifa_flags;   /* Flags as from SIOCGIFFLAGS ioctl.  */
    
      struct sockaddr *ifa_addr;    /* Network address of this interface.  */
      struct sockaddr *ifa_netmask; /* Netmask of this interface.  */
      union
      {
        /* At most one of the following two is valid.  If the IFF_BROADCAST
           bit is set in `ifa_flags', then `ifa_broadaddr' is valid.  If the
           IFF_POINTOPOINT bit is set, then `ifa_dstaddr' is valid.
           It is never the case that both these bits are set at once.  */
        struct sockaddr *ifu_broadaddr; /* Broadcast address of this interface. */
        struct sockaddr *ifu_dstaddr; /* Point-to-point destination address.  */
      } ifa_ifu;
      /* These very same macros are defined by <net/if.h> for `struct ifaddr'.
         So if they are defined already, the existing definitions will be fine.  */
    # ifndef ifa_broadaddr
    #  define ifa_broadaddr ifa_ifu.ifu_broadaddr
    # endif
    # ifndef ifa_dstaddr
    #  define ifa_dstaddr   ifa_ifu.ifu_dstaddr
    # endif 
            
      void *ifa_data;       /* Address-specific data (may be unused).  */
    };
    另外这个链表我们是能够提前用ioctl来筛选的,能够通过ifa_name和ifa_flags来确定ifa_ifu里面究竟选用那个union。只是这次我们是来測量实时网速的,不必要关心这个。

    我们须要关心的是ifa_data这个项。关于这个项我百度了非常多。一直没有发现他究竟应该属于哪个结构体的。

    后来无意在http://blog.chinaunix.net/uid-22832715-id-292763.html发现有相似的,可是我找不到头文件在那。所以后来干脆我直接把他放到我的头文件中面;

    struct if_data{
    	/* generic interface information */
    	u_char	ifi_type;	/* ethernet, tokenring, etc */
    	u_char	ifi_addrlen;	/* media address length */
    	u_char	ifi_hdrlen;	/* media header length */
    	u_long	ifi_mtu;	/* maximum transmission unit */
    	u_long	ifi_metric;	/* routing metric (external only) */
    	u_long	ifi_baudrate;	/* linespeed */
    	/* volatile statistics */
    	u_long	ifi_ipackets;	/* packets received on interface */
    	u_long	ifi_ierrors;	/* input errors on interface */
    	u_long	ifi_opackets;	/* packets sent on interface */
    	u_long	ifi_oerrors;	/* output errors on interface */
    	u_long	ifi_collisions;	/* collisions on csma interfaces */
    	u_long	ifi_ibytes;	/* total number of octets received */
    	u_long	ifi_obytes;	/* total number of octets sent */
    	u_long	ifi_imcasts;	/* packets received via multicast */
    	u_long	ifi_omcasts;	/* packets sent via multicast */
    	u_long	ifi_iqdrops;	/* dropped on input, this interface */
    	u_long	ifi_noproto;	/* destined for unsupported protocol */
    	struct	timeval ifi_lastchange;/* last updated */
    };
    刚刚開始我就打印了ifi_iobytes,ifi_obytes这两个项,无论我怎么下载和上次文件,这两个量都是0。

    纠结了我半天。我就直接把全部变量都打印出来。发现ifi_mtu,ifi_metric,ifi_baudrate跟ifconfig eth0输出的数据非常像。

    [15:12 @ ~/program/netspeed]$ ifconfig eth0
    eth0      Link encap:Ethernet  HWaddr 00:22:15:67:F8:16  
              inet addr:210.42.158.204  Bcast:210.42.158.255  Mask:255.255.255.0
              inet6 addr: fe80::222:15ff:fe67:f816/64 Scope:Link
              UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
              RX packets:917978 errors:0 dropped:0 overruns:0 frame:0
              TX packets:1132894 errors:0 dropped:0 overruns:0 carrier:0
              collisions:0 txqueuelen:1000 
              RX bytes:132866544 (126.7 MiB)  TX bytes:1250785627 (1.1 GiB)
              Interrupt:29 Base address:0x4000 
    慢慢的我知道了规律,struct ifaddrs里面的ifa_data前四个字(32位)以此是发送数据包数。接收数据包数,发送字节数,接收字节数。

    我就又一次调整了struct if_data的结构体,因为后面的数据全为0,我就保留了4项:

    struct if_data
    {   
        /*  generic interface information */
        u_long ifi_opackets;    /*  packets sent on interface */
        u_long ifi_ipackets;    /*  packets received on interface */
        u_long ifi_obytes;      /*  total number of octets sent */
        u_long ifi_ibytes;      /*  total number of octets received */
    };  
    測试OK。

    [15:17 @ ~/program/netspeed]$ ./netspeed 
    Get eth0 Speed                  [OK]
    eth0: Up Speed: 1.671066 MB/s || Down Speed: 0.036335 MB/s 
    附上我已经封装好的代码:

    int get_if_dbytes(struct if_info* ndev)
    {   
        assert(ndev);
        
        struct ifaddrs *ifa_list = NULL;
        struct ifaddrs *ifa = NULL;
        struct if_data *ifd = NULL;
        int     ret = 0;
        
        ret = getifaddrs(&ifa_list);
        if(ret < 0) { 
            perror("Get Interface Address Fail:");
            goto end;
        }   
        
        for(ifa=ifa_list; ifa; ifa=ifa->ifa_next){
            if(!(ifa->ifa_flags & IFF_UP) && !(ifa->ifa_flags & IFF_RUNNING))
                continue;
    
            if(ifa->ifa_data == 0)
                continue;
            
            ret = strcmp(ifa->ifa_name,ndev->ifi_name);
            if(ret == 0){
               ifd = (struct if_data *)ifa->ifa_data;
               
               ndev->ifi_ibytes = ifd->ifi_ibytes;
               ndev->ifi_obytes = ifd->ifi_obytes;
               break;
            }
        }
    
        freeifaddrs(ifa_list);
    end:
        return (ret ? -1 : 0);
    }
    
    int get_if_speed(struct if_speed *ndev)
    {
        assert(ndev); 
    
        struct if_info *p1=NULL,*p2=NULL;
    
        p1 = (struct if_info *)malloc(sizeof(struct if_info));
        p2 = (struct if_info *)malloc(sizeof(struct if_info));
        bzero(p1,sizeof(struct if_info));
        bzero(p2,sizeof(struct if_info));
    
        strncpy(p1->ifi_name,ndev->ifs_name,strlen(ndev->ifs_name));
        strncpy(p2->ifi_name,ndev->ifs_name,strlen(ndev->ifs_name));
    
        int ret = 0;
        ret = get_if_dbytes(p1);
        if(ret < 0)     goto end;
        usleep(ndev->ifs_us);
        ret = get_if_dbytes(p2);
        if(ret < 0)     goto end;
    
        ndev->ifs_ispeed = p2->ifi_ibytes - p1->ifi_ibytes;
        ndev->ifs_ospeed = p2->ifi_obytes - p1->ifi_obytes;
    
    end:
        free(p1);
        free(p2);
    
        return 0;
    }

    头文件:

    #ifndef __TSPEED_H__
    #define __TSPEED_H__
    
    #ifdef __cplusplus
    extern "C"
    {
    #endif
        
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <assert.h>
    #include <error.h>
    
        /* For "open" function */
    #include <sys/types.h>
    #include <sys/stat.h>
    #include <fcntl.h>
    struct if_data
    {   
        /*  generic interface information */
        u_long ifi_opackets;    /*  packets sent on interface */
        u_long ifi_ipackets;    /*  packets received on interface */
        u_long ifi_obytes;      /*  total number of octets sent */
        u_long ifi_ibytes;      /*  total number of octets received */
    };
        
    struct if_info
    {   
        char ifi_name[16];
        unsigned long ifi_ibytes;
        unsigned long ifi_obytes;
    };
    struct if_speed
    {   
        char ifs_name[16];
        unsigned long ifs_ispeed;
        unsigned long ifs_ospeed;
        unsigned long ifs_us;
    };
    
    extern int get_if_dbytes(struct if_info *ndev);
    extern int get_if_speed(struct if_speed *ndev);
    
    #ifdef __cplusplus
    }
    #endif
    
    #endif
    測试代码:

    int main (int argc, char **argv)
    {
        struct if_speed ndev;
        int ret = 0;
    
        bzero(&ndev,sizeof(ndev));
        sprintf(ndev.ifs_name,"eth0");
    
        ndev.ifs_us = 100000;
    
        printf("Get %s Speed");
        ret = get_if_speed(&ndev);
        if(ret < 0)
            printf("			[Fail]
    ");
        else
            printf("			[OK]
    ");
        float ispeed ,ospeed;
        while(1){
            ispeed = ndev.ifs_ispeed * 1.0/(ndev.ifs_us/1000 * 0.001);
            ospeed = ndev.ifs_ospeed * 1.0/(ndev.ifs_us/1000 * 0.001);
    
            printf("%s: Up Speed: %f MB/s || Down Speed: %f MB/s                   
    ",
                    ndev.ifs_name,ispeed/(1024.0*1024.0),ospeed/(1024.0*1024.0));
    
            get_if_speed(&ndev);
        }
    
    
        return 0;
    } /* ----- End of main() ----- */

    可能你有更好的获取网速的办法,求留言指点!
  • 相关阅读:
    【Oracle】dba_jobs字段说明
    【工作杂记】一次修改表字段名操作导致的报表缺失了2个小时的数据
    【SAP BO】无法识别账户信息:无法访问CMS。计算机上的CMS由于某个严重错误而停止。(FWM 20031)
    【虚拟机】在VMware中安装Server2008之后配置网络连接的几种方式
    vlc for android 编译过程
    ubuntu19更新源
    nginx错误Too many open files
    mp4流化
    编译ffmpeg的时候出现ERROR: libx264 not found
    nginx中Lua模块内置变量
  • 原文地址:https://www.cnblogs.com/zhchoutai/p/8431137.html
Copyright © 2011-2022 走看看