在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("\t\t\t[Fail]\n"); else printf("\t\t\t[OK]\n"); 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 \r", ndev.ifs_name,ispeed/(1024.0*1024.0),ospeed/(1024.0*1024.0)); get_if_speed(&ndev); } return 0; } /* ----- End of main() ----- */
可能你有更好的獲取網速的辦法,求留言指點!