一、实现基础
在Linux系统中,操作系统屏蔽了用户直接访问系统内核,提供了LKM机制间接在内核空间工作,在LKM机制中一个重要的组成部分就是proc伪文件系统,它为用户提供了动态操作Linux内核信息的接口。linux各个网卡(包含虚拟网卡)信息通过/proc/net/dev文件句柄进行访问获取,例如,采用cat命令读取相关信息,如下:
[py@pyfree net_info_test]$ cat /proc/net/dev
Inter-| Receive | Transmit
face |bytes packets errs drop fifo frame compressed multicast|bytes packets errs drop fifo colls carrier compressed
lo: 264 4 0 0 0 0 0 0 264 4 0 0 0 0 0 0
virbr0-nic: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
virbr0: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
ens33: 75477 809 0 0 0 0 0 0 216531 679 0 0 0 0 0 0
[py@pyfree net_info_test]$
另外借助awk命令, 可以通过 print、printf 将数据输出到标准输出或重定向到文件
[py@pyfree ~]$ cat /proc/net/dev |awk '{ if(NR!=1 && NR!=2) print $0 }' |sed 's/:/ /g'| awk '{ print($1,$2,$3,$5,$10,$11,$13)}'
lo 264 4 0 264 4 0
virbr0-nic 0 0 0 0 0 0
virbr0 0 0 0 0 0 0
ens33 89565 878 0 227278 746 0
[pyg@pyfree ~]$
显然c/c++读取网卡流量信息,就是打开/proc/net/dev管道文件句柄,识别该文件内容格式,从中读取到需要的数据信息。
二、代码实现
工程设计:
net_info_test
bin
src
net.h
net.cpp
main.cpp
Makefile
net.h,定义流量信息结构体,通过popen打开/proc/net/dev获取流量信息
#ifndef _NET_INFO_H_
#define _NET_INFO_H_
/**********************************************************************************
*Copyright 2020-09-28, pyfree
*
*File Name : net.h
*File Mark :
*Summary :
*
*Current Version : 1.00
*Author : pyfree
*FinishDate :
*
*Replace Version :
*Author :
*FinishDate :
***********************************************************************************/
#include <inttypes.h>
typedef struct
{
char netName[32];
uint64_t recvPackets;
uint64_t sendPackets;
uint64_t recvBytes;
uint64_t sendBytes;
uint32_t recvDropPackets;
uint32_t sendDropPackets;
}NetFlowInfo;
void getNetFlowInfo(NetFlowInfo &nfi);
#endif //_NET_INFO_H_
net.cpp
#include <string.h>
#include <stdio.h>
#include "net.h"
#define CMD "/bin/cat /proc/net/dev |awk \'{ if(NR!=1 && NR!=2) print $0 }\' |sed 's/:/ /g'| awk \'{ print $1\" \"$2\" \"$3\" \"$5\" \"$10\" \"$11\" \"$13}\'"
void getNetFlowInfo(NetFlowInfo &nfi)
{
FILE *fp = popen(CMD, "r");
if(fp == NULL) {
return ;
}
NetFlowInfo stTmp;
bool bUseComm0 = false;
bool bUseComm1 = false;
while( fscanf(fp,"%s%" PRIu64"%" PRIu64"%u%" PRIu64"%" PRIu64"%u",
stTmp.netName, &stTmp.recvBytes, &stTmp.recvPackets, &stTmp.recvDropPackets,
&stTmp.sendBytes, &stTmp.sendPackets, &stTmp.sendDropPackets) == 7)
{
if(strstr(stTmp.netName, nfi.netName)){
memcpy(&nfi, &stTmp, sizeof(stTmp));
}
}
pclose(fp);
}
main.cpp,可以自行依据运行环境修改需要监测的网络名称
#include <stdio.h>
#include <string.h>
#include "net.h"
int main(int argc, char* argv[])
{
NetFlowInfo sfi = {0};
//自行依据运行环境修改需要监测的网络名称,可以ifconfig先查看有那些网络名
strncpy(sfi.netName, "ens33", sizeof(sfi.netName));
getNetFlowInfo(sfi);
printf("\nread inter:%s, \nrecv - \nbytes:%" PRIu64" \npackets:%" PRIu64" \ndrop:%u ; \nsend - "
"\nbytes:%" PRIu64" \npackets:%" PRIu64" \ndrop:%u ;",
sfi.netName, sfi.recvBytes, sfi.recvPackets, sfi.recvDropPackets,
sfi.sendBytes, sfi.sendPackets, sfi.sendDropPackets);
//system("read");
return 0;
}
三、编译
Makefile
#/bin/sh
CX= g++
BIN := ./bin
TARGET := net_test.bin
FLAGS := -std=c++11
#-static
SRCDIR := ./src
#INCLUDES
INCLUDEDIR := -I"$(SRCDIR)"
source := $(wildcard $(SRCDIR)/*.cpp)
$(TARGET) :
$(CX) $(FLAGS) $(INCLUDEDIR) $(source) -o $(BIN)/$(TARGET)
clean:
rm $(BIN)/$(TARGET)
编译及输出结果:
[py@pyfree net_info_test]$ make
g++ -std=c++11 -I"./src" ./src/net.cpp ./src/main.cpp -o ./bin/net_test.bin
[py@pyfree net_info_test]$ ./bin/net_test.bin
read inter:ens33,
recv -
bytes:95854
packets:950
drop:0 ;
send -
bytes:236500
packets:794
drop:0 ;
[py@pyfree net_info_test]$
注:类似地,可以实现对linux系统其他系统信息的实时读取