cat /proc/net/dev
Linux 内核提供了一种通过 /proc 文件系统,在运行时访问内核内部数据结构、改变内核设置的机制。proc文件系统是一个伪文件系统,它只存在内存当中,而不占用外存空间。它以文件系统的方式为访问系统内核数据的操作提供接口。用户和应用程序可以通过proc得到系统的信息,并可以改变内核的某些参数。由于系统的信息,如进程,是动态改变的,所以用户或应用程序读取proc文件时,proc文件系统是动态从系统内核读出所需信息并提交的。
/proc文件系统中包含了很多目录,其中/proc/net/dev就是提供给用户读取或更改网络适配器及统计信息的途径。
注意:因为proc是伪文件系统,只存在内存中,所以这里统计的数据的时间起止时间是:系统启动到命令执行,如果此时系统发生重启,数据将会清零。
参数说明:
bytes: 接口发送或接收的数据的总字节数
packets: 接口发送或接收的数据包总数
errs: 由设备驱动程序检测到的发送或接收错误的总数
drop: 设备驱动程序丢弃的数据包总数
fifo: FIFO缓冲区错误的数量
frame: 分组帧错误的数量
colls: 接口上检测到的冲突数
compressed: 设备驱动程序发送或接收的压缩数据包数
carrier: 由设备驱动程序检测到的载波损耗的数量
multicast: 设备驱动程序发送或接收的多播帧数
其实,我们平时经常用的很多查看网卡实时流量的命令,都是通过读取该目录下的实时流量,并通过简单计算得到的。
#include <stdio.h>
#include <string.h>
#include <stdbool.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
// 更改为你要监测的网卡名称,可以通过ifconfig获得
#define INTERFACE_NAME "ens33"
unsigned long long ticBytes;
unsigned long long tocBytes;
// 读取指定网卡的统计信息
int readInterfaceStats(const char *interfaceName, bool isTic) {
FILE *file = fopen("/proc/net/dev", "r");
if (file == NULL) {
printf("Failed to open /proc/net/dev");
return -1;
}
char line[256];
while (fgets(line, sizeof(line), file)) {
if (strstr(line, interfaceName) != NULL) {
if (isTic) {
// 读取bytes的相关信息,用%*s跳过无用字符串
sscanf(line, "%*s %llu", &ticBytes);
}
else {
sscanf(line, "%*s %llu", &tocBytes);
}
fclose(file);
return 0;
}
}
fclose(file);
return -1;
}
long *myIfconfig(char *interfaceName)
{
int fd = open("/proc/net/dev", O_RDONLY | O_EXCL);
if (-1 == fd)
{
printf("/proc/net/dev not exists!\n");
return NULL;
}
char buf[1024*2];
lseek(fd, 0, SEEK_SET);
int nBytes = read(fd, buf, sizeof(buf)-1);
if (-1 == nBytes)
{
printf("read error");
close(fd);
return NULL;
}
buf[nBytes] = '\0';
close(fd);
//返回第一次指向netCard位置的指针
char* pDev = strstr(buf, interfaceName);
if (NULL == pDev)
{
printf("don't find dev %s\n", interfaceName);
return NULL;
}
char *p;
char *ifconfigValue;
int i = 0;
static long rx2Tx10[2];
/*去除空格,制表符,换行符等不需要的字段*/
for (p = strtok(pDev, " \t\r\n"); p; p = strtok(NULL, " \t\r\n"))
{
i++;
ifconfigValue = (char*)malloc(20);
strcpy(ifconfigValue, p);
/*得到的字符串中的第二个字段是接收流量*/
if(i == 2)
{
rx2Tx10[0] = atol(ifconfigValue);
}
/*得到的字符串中的第十个字段是发送流量*/
if(i == 10)
{
rx2Tx10[1] = atol(ifconfigValue);
break;
}
free(ifconfigValue);
}
return rx2Tx10;
}
int main()
{
double interval = 1.0; // 采样间隔,单位为秒
while (1) {
if (readInterfaceStats(INTERFACE_NAME, true) == -1) {
printf("Failed to read interface stats\n");
return -1;
}
sleep((unsigned int)interval);
if (readInterfaceStats(INTERFACE_NAME, false) == -1) {
printf("Failed to read interface stats\n");
return -1;
}
double kbps = (tocBytes - ticBytes) / interval / 1024;
printf("receive speed is Kb/s: %.2f\n", kbps);
long *ifconfigResult;
double reKb;
ifconfigResult = myIfconfig(INTERFACE_NAME);
reKb = (double)ifconfigResult[0] / (1024);
printf("Receive total: %0.2f KB\n", reKb);
reKb = (double)ifconfigResult[1] / (1024);
printf("Send total: %0.2f KB\n", reKb);
}
return 0;
}