Linux系统资源使用情况监控

任务目标

在基于Linux系统的主机上,对主机运行状态进行监控linux系统内存查询命令,评判终端负载情况。相当于简单的系统资源管理器功能。该设计目标是实现对:

(1)CPU占用率

(2)系统运行时长

(3)显存占用率

(4)网路插口属性

(5)网卡速度信息

的监控。

CPU占用率

我们通过读取/proc/stat文件获取当前系统的CPU占用率。

/proc文件系统

proc是一个只存在显存当中的伪文件系统。它以文件系统的方法为内核与进程提供通讯的插口。用户和应用程序可以通过/proc得到动态的从系统内核读出的系统的信息,并可以改变内核的个别参数。

/proc/stat

/proc/stat包含了系统启动以来的许多关于kernel和系统的统计信息,其中包括CPU运行情况、中断统计、启动时间、上下文切换次数、运行中的进程等等信息。虽然,/proc/stat反映的就是CPU总的占用时间,如右图所示。

[CPU指标]:user,nice,system,idle,iowait,irq,softirq

第一行内容表示总的CPU信息,假如主机有多核,会有多个CPU0~n;

CPU借助率的估算

CPU借助率分为用户态,系统态和空闲态,分别表示CPU处于用户态执行的时间,系统内核执行的时间linux查看磁盘空间,和空闲系统进程执行的时间。平常所说的CPU借助率是指:CPU执行非系统空闲进程的时间/CPU总的执行时间。

1.定义CPU信息结构体linux系统内存查询命令,用于储存各模式下的CPU使用时间。

typedef struct _CPU_PACKED
{
  char name[16];
  unsigned int user;   //用户模式
  unsigned int nice;   //低优先级的用户模式
  unsigned int system; //内核模式
  unsigned int idle;   //空闲处理器时间
} CPU_OCCUPY;

2.打开/proc/stat文件,借助sscanf函数读取须要的数据。

  fd = fopen("/proc/stat", "r");
  if (fd == NULL) {
      perror("open /proc/stat failedn");
      exit(0);
  }
  fgets(buff, sizeof(buff), fd);
  sscanf(buff, "%s %u %u %u %u", cpu->name, &cpu->user, &cpu->nice, &cpu->system, &cpu->idle);
  fclose(fd);

估算方式:

t1:第一次采集(用户+优先级+系统+空闲)的时间过一段时间,ex:sleep(1);t2:第二次(用户+优先级+系统+空闲)的时间user:用户模式第一次和第二次的时间之差system:系统第一次和第二次的时间之差

linux清理内存命令_linux系统内存查询命令_linux查看硬盘内存命令

显存、运行时长

Linux中,sysinfo是拿来获取系统相关信息的结构体。

具体定义如下:

通过sysinfo函数获取上述结构体信息。

    int ret = 0;
    ret = sysinfo(&info);
    if (ret != 0) {
        perror("get sys_info failedn");
        exit(0);
    }

定义主机状态信息结构体(如下),以保存主机的时长、使用率信息。

/*主机的状态信息结构体*/
typedef struct _HOST_STATE{
    int hour;
    int minute;
    double cpu_used;
    double mem_used ;
}HOST_STATE;

系统运行时间

通过uptime参数获取

显存借助率

通过totalram、freeram参数获取

网路插口属性ifreq、ifconf结构体

ifreq结构定义在/usr/include/net/if.h,拿来配置ip地址,激活插口,配置MTU等插口信息的。其中包含了一个插口的名子和具体内容——(是个共用体,有可能是IP地址,广播地址,子网网段linux应用程序,MAC号,MTU或其他内容)。

ifreq包含在ifconf结构中。而ifconf结构一般是拿来保存所有插口的信息的。

网卡插口名称、MAC地址、IP地址就保存于以下数组中。通过ifconf结构体我们可以获取到本机当前所有活动网卡的相关属性。

/proc/net/dev

/proc/net/dev文件就是提供给用户读取或修改网路适配器及统计信息的途径

interface:插口的名子Receive:表示收包Transmit:表示收包bytes:表示收发的字节数

为了储存网卡相关信息,定义如下结构体。

同时采用数组结构动态储存网卡统计信息,以实现获取本机上的所有网卡设备。

/*网卡设备信息结构体*/
typedef struct _NET_INTERFACE
{
  char name[16];  /*网络接口名称*/
  char ip[16];    /*网口IP*/
  double d_speed; /*下行速度*/
  double u_speed; /*上行速度*/
  char mac[13];   /*网口MAC地址*/
  /*上下行速度级别 bit 7~0
  *bit[0]=d_speed  
  *bit[1]=u_speed 
  *1:MB/s 0:KB/s
  */
  unsigned char speed_level;   /**/
  struct _NET_INTERFACE *next; /*链表指针*/
} NET_INTERFACE;

网速估算

定义RTX_BYTES结构体用于储存网卡特定时刻的收分包情况。

/*收发数据包结构体*/
typedef struct _RTX_BYTES
{
  long int tx_bytes;
  long int rx_bytes;
  struct timeval rtx_time;
} RTX_BYTES;

通过打开/proc/net/dev文件,按行读取可获得各网卡当前时刻总的收分包信息。程序示例如下。

    open_netconf(&net_dev_file);
    //获取时间
    gettimeofday(&rtx->rtx_time, NULL);
    //从第三行开始读取网络接口数据
    while ((read = getline(&line, &bytes_read, net_dev_file)) != -1) {
        if ((++i) <= 2)
            continue;
        if (strstr(line, name) != NULL) {
            memset(str1, 0x0, 32);
            memset(str2, 0x0, 32);
            sscanf(line, "%*s%s%*s%*s%*s%*s%*s%*s%*s%s", str1, str2);
            rtx->tx_bytes = atol(str2);
            rtx->rx_bytes = atol(str1);
#if DEBUG
            printf("name:%8st tx:ldtrx:ldn", name, rtx->tx_bytes, rtx->rx_bytes);
#endif
        }
    }
    fclose(net_dev_file);

网速的估算同CPU借助率估算一样,都须要通过两次采集,统计特定时间间隔内的信息来估算。

估算方式:

t1:当前时刻收分包字节数bytes1过一段时间,ex:sleep(1);t2:当前时间收分包字节数bytes2

程序示例:首先回来两次采集的间隔时长,再通过收分包字节数估算上下行网速。

 long int time_lapse;
    time_lapse = (rtx1->rtx_time.tv_sec * 1000 + rtx1->rtx_time.tv_usec / 1000) - (rtx0->rtx_time.tv_sec * 1000 + rtx0->rtx_time.tv_usec / 1000);
    *d_speed = (rtx1->rx_bytes - rtx0->rx_bytes) * 1.0 / (1024 * time_lapse * 1.0 / 1000);
    *u_speed = (rtx1->tx_bytes - rtx0->tx_bytes) * 1.0 / (1024 * time_lapse * 1.0 / 1000);

程序流程

项目中共设计两个线程分别采集网速信息、CPU&显存&运行时长信息。整体流程如下。

main函数展示:

    int nums = 0;
    //网卡结构体指针初始化
    p_interface = (NET_INTERFACE *)malloc(sizeof(NET_INTERFACE));
    //获取本机网卡数量
    get_interface_info(&p_interface, &nums);
    printf("net_interface nums: %dn", nums);
    show_netinterfaces(p_interface, 0);
    //创建两个线程
    pthread_t thread_net_id, thread_core_id;
    //线程1:网络信息监控线程
    pthread_create(&thread_net_id, NULL, (void *)thread_net, NULL);
    //线程2:CPU、内存信息监控
    pthread_create(&thread_core_id, NULL, (void *)thread_core, NULL);

结果展示

终端可持续实时输出CPU、内存、运行时间,网卡IP、MAC、上下行速度信息。

再与本机的监控软件信息对比,证明输出结果可信。

监控软件显示的CPU、内存使用信息:

输出本机网卡信息:

完整的项目地址github

gitee

Author

这篇优质的内容由TA贡献而来

刘遄

《Linux就该这么学》书籍作者,RHCA认证架构师,教育学(计算机专业硕士)。

发表回复