- 論壇徽章:
- 0
|
在Windows下面,我們可以看到360或者是qq安全衛(wèi)士的“安全球”,上面顯示實(shí)時(shí)的網(wǎng)速情況。那么在Linux里面如何獲取網(wǎng)卡的實(shí)時(shí)網(wǎng)速?其實(shí)原理很簡(jiǎn)單,讀取需要獲取網(wǎng)速的網(wǎng)卡在某段時(shí)間dT內(nèi)流量的變化dL,那么實(shí)時(shí)網(wǎng)速就出來了,Speed = dL / dt。
Linux在ifaddrs.h中提供了函數(shù):- /* 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;
復(fù)制代碼
系統(tǒng)會(huì)創(chuàng)建一個(gè)包含本機(jī)所有網(wǎng)卡信息鏈表,然后我們就可以在這個(gè)鏈表里面獲取我們想要的信息。- /* 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). */
- };
復(fù)制代碼
另外這個(gè)鏈表我們是可以提前用ioctl來篩選的,可以通過ifa_name和ifa_flags來確定ifa_ifu里面到底選用那個(gè)union。不過這次我們是來測(cè)量實(shí)時(shí)網(wǎng)速的,不必要關(guān)心這個(gè)。
我們需要關(guān)心的是ifa_data這個(gè)項(xiàng),關(guān)于這個(gè)項(xiàng)我百度了很多,一直沒有發(fā)現(xiàn)他到底應(yīng)該屬于哪個(gè)結(jié)構(gòu)體的。
后來無意在網(wǎng)上找了一些發(fā)現(xiàn)有類似的,但是我找不到頭文件在那,所以后來干脆我直接把他放到我的頭文件里面;- 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 */
- };
復(fù)制代碼
剛剛開始我就打印了ifi_iobytes,ifi_obytes這兩個(gè)項(xiàng),不管我怎么下載和上次文件,這兩個(gè)量都是0。糾結(jié)了我半天,我就直接把所有變量都打印出來,發(fā)現(xiàn)ifi_mtu,ifi_metric,ifi_baudrate跟ifconfig eth0輸出的數(shù)據(jù)很像。- [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
復(fù)制代碼
慢慢的我知道了規(guī)律,struct ifaddrs里面的ifa_data前四個(gè)字(32位)以此是發(fā)送數(shù)據(jù)包數(shù),接收數(shù)據(jù)包數(shù),發(fā)送字節(jié)數(shù),接收字節(jié)數(shù)。
我就重新調(diào)整了struct if_data的結(jié)構(gòu)體,由于后面的數(shù)據(jù)全為0,我就保留了4項(xiàng):- 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 */
- };
復(fù)制代碼
測(cè)試OK。- [15:17 @ ~/program/netspeed]$ ./netspeed
- Get eth0 Speed [OK]
- eth0: Up Speed: 1.671066 MB/s || Down Speed: 0.036335 MB/s
復(fù)制代碼
附上我已經(jīng)封裝好的代碼:- 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;
- }
復(fù)制代碼
頭文件:- #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
復(fù)制代碼
測(cè)試代碼:- 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() ----- */
復(fù)制代碼 |
|