免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 3665 | 回复: 0
打印 上一主题 下一主题

[Linux] 获取网卡的实时网速 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2015-05-25 11:09 |只看该作者 |倒序浏览
在Windows下面,我们可以看到360或者是qq安全卫士的“安全球”,上面显示实时的网速情况。那么在Linux里面如何获取网卡的实时网速?其实原理很简单,读取需要获取网速的网卡在某段时间dT内流量的变化dL,那么实时网速就出来了,Speed = dL / dt。

Linux在ifaddrs.h中提供了函数:
  1. /* Create a linked list of `struct ifaddrs' structures, one for each
  2.   network interface on the host machine.  If successful, store the
  3.   list in *IFAP and return 0.  On errors, return -1 and set `errno'.
  4.             
  5.   The storage returned in *IFAP is allocated dynamically and can
  6.   only be properly freed by passing it to `freeifaddrs'.  */
  7. extern int getifaddrs (struct ifaddrs **__ifap) __THROW;
  8.          
  9. /* Reclaim the storage allocated by a previous `getifaddrs' call.  */
  10. extern void freeifaddrs (struct ifaddrs *__ifa)  __THROW;
复制代码

系统会创建一个包含本机所有网卡信息链表,然后我们就可以在这个链表里面获取我们想要的信息。
  1. /* The `getifaddrs' function generates a linked list of these structures.
  2.   Each element of the list describes one network interface.  */
  3. struct ifaddrs
  4. {
  5.   struct ifaddrs *ifa_next; /* Pointer to the next structure.  */

  6.   char *ifa_name;      /* Name of this network interface.  */
  7.   unsigned int ifa_flags;  /* Flags as from SIOCGIFFLAGS ioctl.  */

  8.   struct sockaddr *ifa_addr;    /* Network address of this interface.  */
  9.   struct sockaddr *ifa_netmask; /* Netmask of this interface.  */
  10.   union
  11.   {
  12.     /* At most one of the following two is valid.  If the IFF_BROADCAST
  13.       bit is set in `ifa_flags', then `ifa_broadaddr' is valid.  If the
  14.       IFF_POINTOPOINT bit is set, then `ifa_dstaddr' is valid.
  15.       It is never the case that both these bits are set at once.  */
  16.     struct sockaddr *ifu_broadaddr; /* Broadcast address of this interface. */
  17.     struct sockaddr *ifu_dstaddr; /* Point-to-point destination address.  */
  18.   } ifa_ifu;
  19.   /* These very same macros are defined by <net/if.h> for `struct ifaddr'.
  20.     So if they are defined already, the existing definitions will be fine.  */
  21. # ifndef ifa_broadaddr
  22. #  define ifa_broadaddr ifa_ifu.ifu_broadaddr
  23. # endif
  24. # ifndef ifa_dstaddr
  25. #  define ifa_dstaddr  ifa_ifu.ifu_dstaddr
  26. # endif
  27.         
  28.   void *ifa_data;      /* Address-specific data (may be unused).  */
  29. };
复制代码

另外这个链表我们是可以提前用ioctl来筛选的,可以通过ifa_name和ifa_flags来确定ifa_ifu里面到底选用那个union。不过这次我们是来测量实时网速的,不必要关心这个。

我们需要关心的是ifa_data这个项,关于这个项我百度了很多,一直没有发现他到底应该属于哪个结构体的。
后来无意在网上找了一些发现有类似的,但是我找不到头文件在那,所以后来干脆我直接把他放到我的头文件里面;
  1. struct if_data{
  2. /* generic interface information */
  3. u_char ifi_type; /* ethernet, tokenring, etc */
  4. u_char ifi_addrlen; /* media address length */
  5. u_char ifi_hdrlen; /* media header length */
  6. u_long ifi_mtu; /* maximum transmission unit */
  7. u_long ifi_metric; /* routing metric (external only) */
  8. u_long ifi_baudrate; /* linespeed */
  9. /* volatile statistics */
  10. u_long ifi_ipackets; /* packets received on interface */
  11. u_long ifi_ierrors; /* input errors on interface */
  12. u_long ifi_opackets; /* packets sent on interface */
  13. u_long ifi_oerrors; /* output errors on interface */
  14. u_long ifi_collisions; /* collisions on csma interfaces */
  15. u_long ifi_ibytes; /* total number of octets received */
  16. u_long ifi_obytes; /* total number of octets sent */
  17. u_long ifi_imcasts; /* packets received via multicast */
  18. u_long ifi_omcasts; /* packets sent via multicast */
  19. u_long ifi_iqdrops; /* dropped on input, this interface */
  20. u_long ifi_noproto; /* destined for unsupported protocol */
  21. struct timeval ifi_lastchange;/* last updated */
  22. };
复制代码

刚刚开始我就打印了ifi_iobytes,ifi_obytes这两个项,不管我怎么下载和上次文件,这两个量都是0。纠结了我半天,我就直接把所有变量都打印出来,发现ifi_mtu,ifi_metric,ifi_baudrate跟ifconfig eth0输出的数据很像。
  1. [15:12 @ ~/program/netspeed]$ ifconfig eth0
  2. eth0      Link encap:Ethernet  HWaddr 00:22:15:67:F8:16  
  3.           inet addr:210.42.158.204  Bcast:210.42.158.255  Mask:255.255.255.0
  4.           inet6 addr: fe80::222:15ff:fe67:f816/64 Scope:Link
  5.           UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
  6.           RX packets:917978 errors:0 dropped:0 overruns:0 frame:0
  7.           TX packets:1132894 errors:0 dropped:0 overruns:0 carrier:0
  8.           collisions:0 txqueuelen:1000
  9.           RX bytes:132866544 (126.7 MiB)  TX bytes:1250785627 (1.1 GiB)
  10.           Interrupt:29 Base address:0x4000
复制代码

慢慢的我知道了规律,struct ifaddrs里面的ifa_data前四个字(32位)以此是发送数据包数,接收数据包数,发送字节数,接收字节数。

我就重新调整了struct if_data的结构体,由于后面的数据全为0,我就保留了4项:
  1. struct if_data
  2. {  
  3.     /*  generic interface information */
  4.     u_long ifi_opackets;    /*  packets sent on interface */
  5.     u_long ifi_ipackets;    /*  packets received on interface */
  6.     u_long ifi_obytes;      /*  total number of octets sent */
  7.     u_long ifi_ibytes;      /*  total number of octets received */
  8. };
复制代码

测试OK。
  1. [15:17 @ ~/program/netspeed]$ ./netspeed
  2. Get eth0 Speed                  [OK]
  3. eth0: Up Speed: 1.671066 MB/s || Down Speed: 0.036335 MB/s
复制代码

附上我已经封装好的代码:
  1. int get_if_dbytes(struct if_info* ndev)
  2. {  
  3.     assert(ndev);
  4.    
  5.     struct ifaddrs *ifa_list = NULL;
  6.     struct ifaddrs *ifa = NULL;
  7.     struct if_data *ifd = NULL;
  8.     int    ret = 0;
  9.    
  10.     ret = getifaddrs(&ifa_list);
  11.     if(ret < 0) {
  12.         perror("Get Interface Address Fail:");
  13.         goto end;
  14.     }  
  15.    
  16.     for(ifa=ifa_list; ifa; ifa=ifa->ifa_next){
  17.         if(!(ifa->ifa_flags & IFF_UP) && !(ifa->ifa_flags & IFF_RUNNING))
  18.             continue;

  19.         if(ifa->ifa_data == 0)
  20.             continue;
  21.         
  22.         ret = strcmp(ifa->ifa_name,ndev->ifi_name);
  23.         if(ret == 0){
  24.           ifd = (struct if_data *)ifa->ifa_data;
  25.          
  26.           ndev->ifi_ibytes = ifd->ifi_ibytes;
  27.           ndev->ifi_obytes = ifd->ifi_obytes;
  28.           break;
  29.         }
  30.     }

  31.     freeifaddrs(ifa_list);
  32. end:
  33.     return (ret ? -1 : 0);
  34. }

  35. int get_if_speed(struct if_speed *ndev)
  36. {
  37.     assert(ndev);

  38.     struct if_info *p1=NULL,*p2=NULL;

  39.     p1 = (struct if_info *)malloc(sizeof(struct if_info));
  40.     p2 = (struct if_info *)malloc(sizeof(struct if_info));
  41.     bzero(p1,sizeof(struct if_info));
  42.     bzero(p2,sizeof(struct if_info));

  43.     strncpy(p1->ifi_name,ndev->ifs_name,strlen(ndev->ifs_name));
  44.     strncpy(p2->ifi_name,ndev->ifs_name,strlen(ndev->ifs_name));

  45.     int ret = 0;
  46.     ret = get_if_dbytes(p1);
  47.     if(ret < 0)    goto end;
  48.     usleep(ndev->ifs_us);
  49.     ret = get_if_dbytes(p2);
  50.     if(ret < 0)    goto end;

  51.     ndev->ifs_ispeed = p2->ifi_ibytes - p1->ifi_ibytes;
  52.     ndev->ifs_ospeed = p2->ifi_obytes - p1->ifi_obytes;

  53. end:
  54.     free(p1);
  55.     free(p2);

  56.     return 0;
  57. }
复制代码

头文件:
  1. #ifndef __TSPEED_H__
  2. #define __TSPEED_H__

  3. #ifdef __cplusplus
  4. extern "C"
  5. {
  6. #endif
  7.    
  8. #include <stdio.h>
  9. #include <stdlib.h>
  10. #include <string.h>
  11. #include <assert.h>
  12. #include <error.h>

  13.     /* For "open" function */
  14. #include <sys/types.h>
  15. #include <sys/stat.h>
  16. #include <fcntl.h>
  17. struct if_data
  18. {  
  19.     /*  generic interface information */
  20.     u_long ifi_opackets;    /*  packets sent on interface */
  21.     u_long ifi_ipackets;    /*  packets received on interface */
  22.     u_long ifi_obytes;      /*  total number of octets sent */
  23.     u_long ifi_ibytes;      /*  total number of octets received */
  24. };
  25.    
  26. struct if_info
  27. {  
  28.     char ifi_name[16];
  29.     unsigned long ifi_ibytes;
  30.     unsigned long ifi_obytes;
  31. };
  32. struct if_speed
  33. {  
  34.     char ifs_name[16];
  35.     unsigned long ifs_ispeed;
  36.     unsigned long ifs_ospeed;
  37.     unsigned long ifs_us;
  38. };

  39. extern int get_if_dbytes(struct if_info *ndev);
  40. extern int get_if_speed(struct if_speed *ndev);

  41. #ifdef __cplusplus
  42. }
  43. #endif

  44. #endif
复制代码

测试代码:
  1. int main (int argc, char **argv)
  2. {
  3.     struct if_speed ndev;
  4.     int ret = 0;

  5.     bzero(&ndev,sizeof(ndev));
  6.     sprintf(ndev.ifs_name,"eth0");

  7.     ndev.ifs_us = 100000;

  8.     printf("Get %s Speed");
  9.     ret = get_if_speed(&ndev);
  10.     if(ret < 0)
  11.         printf("\t\t\t[Fail]\n");
  12.     else
  13.         printf("\t\t\t[OK]\n");
  14.     float ispeed ,ospeed;
  15.     while(1){
  16.         ispeed = ndev.ifs_ispeed * 1.0/(ndev.ifs_us/1000 * 0.001);
  17.         ospeed = ndev.ifs_ospeed * 1.0/(ndev.ifs_us/1000 * 0.001);

  18.         printf("%s: Up Speed: %f MB/s || Down Speed: %f MB/s                  \r",
  19.                 ndev.ifs_name,ispeed/(1024.0*1024.0),ospeed/(1024.0*1024.0));

  20.         get_if_speed(&ndev);
  21.     }


  22.     return 0;
  23. } /* ----- End of main() ----- */
复制代码
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP