├── Makefile ├── README.md ├── terminal_monitor.c └── terminal_monitor.h /Makefile: -------------------------------------------------------------------------------- 1 | TARGET= terminal_monitor 2 | OBJS = terminal_monitor.o 3 | 4 | CC = gcc 5 | CFLAGS = -Wall -O2 6 | 7 | RM = rm -f 8 | 9 | $(TARGET):$(OBJS) 10 | $(CC) -o $(TARGET) $(OBJS) $(CFLAGS) -lpthread 11 | $(OBJS):%.o:%.c 12 | $(CC) -c $(CFLAGS) $< -o $@ 13 | .PHONY:clean 14 | clean: 15 | -$(RM) $(TARGET) $(OBJS) 16 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Linux_terminal_monitor 2 | 3 | #### 介绍 4 | 在基于Linux系统的主机上,通过C/C++实现对主机状态监控,衡量终端负载情况。 5 | 设计目标是实现对: 6 | (1)CPU占用率 7 | (2)系统运行时长 8 | (3)内存占用率 9 | (4)网络接口属性:接口名、IP地址、MAC地址 10 | (5)网卡速率信息:上下行网速 11 | 的监控。 12 | 13 | #### 软件架构 14 | 软件架构说明 15 | terminal_monitor.h 16 | terminal_monitor.c 17 | Makefile 18 | 19 | #### 安装教程 20 | 21 | 1. 下载程序源文件 22 | 2. make 23 | 3. ./terminal_monitor 24 | 25 | 26 | -------------------------------------------------------------------------------- /terminal_monitor.c: -------------------------------------------------------------------------------- 1 | /* 2 | * @Description: 3 | * @Version: 1.0 4 | * @Autor: Ming 5 | * @Date: 2021-01-17 22:40:46 6 | * @LastEditors: Ming 7 | * @LastEditTime: 2021-12-04 21:22:03 8 | */ 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | #include 15 | //多线程处理库 16 | #include 17 | //网络监控部分 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | 24 | #include "terminal_monitor.h" 25 | 26 | /*文件/proc/net/dev*/ 27 | FILE *net_dev_file = NULL; 28 | /*本机网络接口信息结构体*/ 29 | NET_INTERFACE *p_interface = NULL; 30 | 31 | HOST_STATE host_core; 32 | 33 | void *thread_net(void *arg) 34 | { 35 | printf("%s\n", __FUNCTION__); 36 | 37 | while (1) { 38 | printf("\n***********************************************************\n"); 39 | get_network_speed(p_interface); 40 | show_netinterfaces(p_interface, 1); 41 | } 42 | } 43 | 44 | void *thread_core(void *arg) 45 | { 46 | printf("%s\n", __FUNCTION__); 47 | while (1) { 48 | open_sysinfo(); 49 | 50 | get_host_runtime(&host_core.hour, &host_core.minute); 51 | printf("\n[run]:%6d hours\t%2d minutes\t", host_core.hour, 52 | host_core.minute); 53 | 54 | get_mem_usage(&host_core.mem_used); 55 | printf("[mem_used]:%6.2f%%\t", host_core.mem_used); 56 | 57 | get_cpu_usage(&(host_core.cpu_used)); 58 | printf("[cpu_used]:%6.2f%%\n", host_core.cpu_used); 59 | sleep(10); 60 | } 61 | } 62 | 63 | void get_cpuoccupy(CPU_OCCUPY *cpu) 64 | { 65 | 66 | char buff[BUFFSIZE]; 67 | FILE *fd; 68 | 69 | /* /proc/stat 包含了系统启动以来的许多关于kernel和系统的统计信息, 70 | 其中包括CPU运行情况、中断统计、启动时间、上下文切换次数、 71 | 运行中的进程等等信息 */ 72 | fd = fopen("/proc/stat", "r"); 73 | if (fd == NULL) { 74 | perror("open /proc/stat failed\n"); 75 | exit(0); 76 | } 77 | fgets(buff, sizeof(buff), fd); 78 | 79 | sscanf(buff, "%s %u %u %u %u", cpu->name, &cpu->user, &cpu->nice, 80 | &cpu->system, &cpu->idle); 81 | fclose(fd); 82 | } 83 | 84 | double cal_occupy(CPU_OCCUPY *c1, CPU_OCCUPY *c2) 85 | { 86 | double t1, t2; 87 | double id, sd; 88 | double cpu_used; 89 | 90 | t1 = (double)(c1->user + c1->nice + c1->system + c1->idle); 91 | t2 = (double)(c2->user + c2->nice + c2->system + c2->idle); 92 | 93 | id = (double)(c2->user - c1->user); 94 | sd = (double)(c2->system - c1->system); 95 | 96 | cpu_used = (100 * (id + sd) / (t2 - t1)); 97 | return cpu_used; 98 | } 99 | 100 | void open_sysinfo() 101 | { 102 | int ret = 0; 103 | ret = sysinfo(&info); 104 | if (ret != 0) { 105 | perror("get sys_info failed\n"); 106 | exit(0); 107 | } 108 | } 109 | 110 | void get_mem_usage(double *mem_used) 111 | { 112 | 113 | FILE *fd; 114 | /************ 115 | ** /proc / meminfo中包含系统允许内存信息 116 | ** 117 | ****/ 118 | 119 | fd = fopen("/proc/meminfo", "r"); 120 | if (fd == NULL) { 121 | perror("open /proc/meminfo failed\n"); 122 | exit(0); 123 | } 124 | 125 | size_t bytes_read; 126 | size_t read; 127 | char *line = NULL; 128 | /************ 129 | *mem_used = total-memavailable 130 | *******/ 131 | int index = 0; 132 | int avimem = 0; 133 | 134 | while ((read = getline(&line, &bytes_read, fd)) != -1) { 135 | if (++index <= 2) { 136 | continue; 137 | } 138 | if (strstr(line, "MemAvailable") != NULL) { 139 | sscanf(line, "%*s%d%*s", &avimem); 140 | 141 | break; 142 | } 143 | } 144 | free(line); 145 | int t = info.totalram / 1024.0; 146 | *mem_used = (t - avimem) * 100 / t; 147 | 148 | #if DEBUG 149 | printf("\n"); 150 | printf("total memory: %.3f\n", info.totalram * 1.0 / 1024 / 1024 / 1024); 151 | printf("free memory: %.3f\n", info.freeram * 1.0 / 1024 / 1024 / 1024); 152 | printf("shared memory: %.3f\n", info.sharedram * 1.0 / 1024 / 1024 / 1024); 153 | printf("buffer memory: %.3f\n", info.bufferram * 1.0 / 1024 / 1024 / 1024); 154 | printf("totalswap memory: %.3f\n", info.totalswap * 1.0 / 1024 / 1024 / 1024); 155 | printf("freeswap memory: %.3f\n", info.freeswap * 1.0 / 1024 / 1024 / 1024); 156 | // printf("memory usage: %.2f%\n", *mem_used); 157 | #endif 158 | fclose(fd); 159 | } 160 | 161 | void get_cpu_usage(double *cpu_used) 162 | { 163 | CPU_OCCUPY cpu_0, cpu_1; 164 | 165 | get_cpuoccupy(&cpu_0); 166 | /* while (1) { 167 | //实现循环监控CPU状态,间隔时间1s */ 168 | sleep(1); 169 | get_cpuoccupy(&cpu_1); 170 | 171 | *cpu_used = cal_occupy(&cpu_0, &cpu_1); 172 | #if DEBUG 173 | printf("cpu: %.2f%\n", *cpu_used); 174 | #endif 175 | /* cpu_0 = cpu_1;//循环监控打开,结构体拷贝赋值语句 176 | } */ 177 | } 178 | 179 | void get_host_runtime(int *hours, int *minutes) 180 | { 181 | *hours = info.uptime / 3600; 182 | *minutes = (info.uptime % 3600) / 60; 183 | #if DEBUG 184 | printf("run time: %ld_hours %d_minutes\n", *hours, *minutes); 185 | #endif 186 | } 187 | 188 | void open_netconf(FILE **fd) 189 | { 190 | *fd = fopen("/proc/net/dev", "r"); 191 | if (*fd == NULL) { 192 | perror("open file /proc/net/dev failed!\n"); 193 | exit(0); 194 | } 195 | } 196 | 197 | void show_netinterfaces(NET_INTERFACE *p_net, int n) 198 | { 199 | NET_INTERFACE *temp; 200 | temp = p_net; 201 | 202 | while (temp != NULL) { 203 | if (!n) { 204 | printf("Interface: %-16s\t IP:%16s\t MAC:%12s\n", temp->name, temp->ip, 205 | temp->mac); 206 | } else { 207 | printf("Interface: %-16s\t", temp->name); 208 | if (temp->speed_level & 0x1) { 209 | printf("download:%10.2lfMB/s\t\t", temp->d_speed); 210 | } else { 211 | printf("download:%10.2lfKB/s\t\t", temp->d_speed); 212 | } 213 | 214 | if ((temp->speed_level >> 1) & 0x1) { 215 | printf("upload:%10.2lfMB/s\n", temp->u_speed); 216 | } else { 217 | printf("upload:%10.2lfKB/s\n", temp->u_speed); 218 | } 219 | } 220 | 221 | temp = temp->next; 222 | } 223 | } 224 | 225 | int get_interface_info(NET_INTERFACE **net, int *n) 226 | { 227 | int fd; 228 | int num = 0; 229 | struct ifreq buf[16]; 230 | struct ifconf ifc; 231 | 232 | NET_INTERFACE *p_temp = NULL; 233 | (*net)->next = NULL; 234 | 235 | if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { 236 | close(fd); 237 | printf("socket open failed\n"); 238 | } 239 | 240 | ifc.ifc_len = sizeof(buf); 241 | ifc.ifc_buf = (caddr_t)buf; 242 | 243 | if (!ioctl(fd, SIOCGIFCONF, (char *)&ifc)) { 244 | // get interface nums 245 | num = ifc.ifc_len / sizeof(struct ifreq); 246 | *n = num; 247 | 248 | // find all interfaces; 249 | while (num-- > 0) { 250 | // exclude lo interface 251 | /* if (!strcmp("lo", buf[num].ifr_name)) 252 | continue; */ 253 | 254 | // get interface name 255 | strcpy((*net)->name, buf[num].ifr_name); 256 | #if DEBUG 257 | printf("name:%8s\t", (*net)->name); 258 | #endif 259 | // get the ipaddress of the interface 260 | if (!(ioctl(fd, SIOCGIFADDR, (char *)&buf[num]))) { 261 | 262 | memset((*net)->ip, 0, 16); 263 | strcpy( 264 | (*net)->ip, 265 | inet_ntoa(((struct sockaddr_in *)(&buf[num].ifr_addr))->sin_addr)); 266 | #if DEBUG 267 | printf("IP:%16s\t", (*net)->ip); 268 | #endif 269 | } 270 | 271 | // get the mac of this interface 272 | if (!ioctl(fd, SIOCGIFHWADDR, (char *)(&buf[num]))) { 273 | 274 | memset((*net)->mac, 0, 13); 275 | 276 | snprintf((*net)->mac, 13, "%02x%02x%02x%02x%02x%02x", 277 | (unsigned char)buf[num].ifr_hwaddr.sa_data[0], 278 | (unsigned char)buf[num].ifr_hwaddr.sa_data[1], 279 | (unsigned char)buf[num].ifr_hwaddr.sa_data[2], 280 | (unsigned char)buf[num].ifr_hwaddr.sa_data[3], 281 | (unsigned char)buf[num].ifr_hwaddr.sa_data[4], 282 | (unsigned char)buf[num].ifr_hwaddr.sa_data[5]); 283 | #if DEBUG 284 | printf("mac:%12s\n", (*net)->mac); 285 | #endif 286 | } 287 | if (num >= 1) { 288 | p_temp = (NET_INTERFACE *)malloc(sizeof(NET_INTERFACE)); 289 | memset(p_temp, 0, sizeof(NET_INTERFACE)); 290 | p_temp->next = *net; 291 | *net = p_temp; 292 | } 293 | } 294 | return 0; 295 | } else { 296 | return -1; 297 | } 298 | } 299 | 300 | void get_rtx_bytes(char *name, RTX_BYTES *rtx) 301 | { 302 | char *line = NULL; 303 | 304 | size_t bytes_read; 305 | size_t read; 306 | 307 | char str1[32]; 308 | char str2[32]; 309 | 310 | int i = 0; 311 | open_netconf(&net_dev_file); 312 | //获取时间 313 | gettimeofday(&rtx->rtx_time, NULL); 314 | //从第三行开始读取网络接口数据 315 | while ((read = getline(&line, &bytes_read, net_dev_file)) != -1) { 316 | if ((++i) <= 2) 317 | continue; 318 | if (strstr(line, name) != NULL) { 319 | memset(str1, 0x0, 32); 320 | memset(str2, 0x0, 32); 321 | 322 | sscanf(line, "%*s%s%*s%*s%*s%*s%*s%*s%*s%s", str1, str2); 323 | 324 | rtx->tx_bytes = atol(str2); 325 | rtx->rx_bytes = atol(str1); 326 | #if DEBUG 327 | printf("name:%16s\t tx:%10ld\trx:%10ld\n", name, rtx->tx_bytes, 328 | rtx->rx_bytes); 329 | #endif 330 | } 331 | } 332 | 333 | free(line); 334 | fclose(net_dev_file); 335 | } 336 | 337 | void rtx_bytes_copy(RTX_BYTES *dest, RTX_BYTES *src) 338 | { 339 | dest->rx_bytes = src->rx_bytes; 340 | dest->tx_bytes = src->tx_bytes; 341 | dest->rtx_time = src->rtx_time; 342 | src->rx_bytes = 0; 343 | src->tx_bytes = 0; 344 | } 345 | 346 | void get_network_speed(NET_INTERFACE *p_net) 347 | { 348 | 349 | RTX_BYTES rtx0, rtx1; 350 | 351 | NET_INTERFACE *temp1, *temp2, *temp3; 352 | temp1 = p_net; 353 | temp2 = p_net; 354 | temp3 = p_net; 355 | while (temp1 != NULL) { 356 | 357 | get_rtx_bytes(temp1->name, &rtx0); 358 | temp1->rtx0_cnt.tx_bytes = rtx0.tx_bytes; 359 | temp1->rtx0_cnt.rx_bytes = rtx0.rx_bytes; 360 | temp1->rtx0_cnt.rtx_time = rtx0.rtx_time; 361 | temp1 = temp1->next; 362 | } 363 | 364 | sleep(WAIT_SECOND); 365 | 366 | while (temp2 != NULL) { 367 | 368 | get_rtx_bytes(temp2->name, &rtx1); 369 | temp2->rtx1_cnt.tx_bytes = rtx1.tx_bytes; 370 | temp2->rtx1_cnt.rx_bytes = rtx1.rx_bytes; 371 | temp2->rtx1_cnt.rtx_time = rtx1.rtx_time; 372 | 373 | temp2->speed_level &= 0x00; 374 | temp2 = temp2->next; 375 | } 376 | // temp->speed_level &= 0x00; 377 | while (temp3 != NULL) { 378 | cal_netinterface_speed(&temp3->u_speed, &temp3->d_speed, 379 | &temp3->speed_level, (&temp3->rtx0_cnt), 380 | (&temp3->rtx1_cnt)); 381 | temp3 = temp3->next; 382 | } 383 | } 384 | 385 | void cal_netinterface_speed(double *u_speed, double *d_speed, 386 | unsigned char *level, RTX_BYTES *rtx0, 387 | RTX_BYTES *rtx1) 388 | { 389 | long int time_lapse; 390 | 391 | time_lapse = (rtx1->rtx_time.tv_sec * 1000 + rtx1->rtx_time.tv_usec / 1000) - 392 | (rtx0->rtx_time.tv_sec * 1000 + rtx0->rtx_time.tv_usec / 1000); 393 | 394 | *d_speed = (rtx1->rx_bytes - rtx0->rx_bytes) * 1.0 / 395 | (1024 * time_lapse * 1.0 / 1000); 396 | *u_speed = (rtx1->tx_bytes - rtx0->tx_bytes) * 1.0 / 397 | (1024 * time_lapse * 1.0 / 1000); 398 | 399 | // speed_level 置0 400 | // *level &= 0x00; 401 | 402 | if (*d_speed >= MB * 1.0) { 403 | *d_speed = *d_speed / 1024; 404 | *level |= 0x1; 405 | #if DEBUG 406 | printf("download:%10.2lfMB/s\t\t", *d_speed); 407 | #endif 408 | } else { 409 | //定义速度级别 410 | *level &= 0xFE; 411 | #if DEBUG 412 | printf("download:%10.2lfKB/s\t\t", *d_speed); 413 | #endif 414 | } 415 | 416 | if (*u_speed >= MB * 1.0) { 417 | *u_speed = *u_speed / 1024; 418 | *level |= 0x1 << 1; 419 | #if DEBUG 420 | printf("upload:%10.2lfMB/s\n", *u_speed); 421 | #endif 422 | } else { 423 | //定义速度级别 424 | *level &= 0xFD; 425 | #if DEBUG 426 | printf("upload:%10.2lfKB/s\n", *u_speed); 427 | #endif 428 | } 429 | } 430 | 431 | int main() 432 | { 433 | int nums = 0; 434 | //网卡结构体指针初始化 435 | p_interface = (NET_INTERFACE *)malloc(sizeof(NET_INTERFACE)); 436 | //获取本机网卡数量 437 | get_interface_info(&p_interface, &nums); 438 | printf("net_interface nums: %d\n", nums); 439 | 440 | show_netinterfaces(p_interface, 0); 441 | //创建两个线程 442 | pthread_t thread_net_id, thread_core_id; 443 | //线程1:网络信息监控线程 444 | pthread_create(&thread_net_id, NULL, (void *)thread_net, NULL); 445 | //线程2:CPU、内存信息监控 446 | pthread_create(&thread_core_id, NULL, (void *)thread_core, NULL); 447 | 448 | pthread_join(thread_net_id, NULL); 449 | pthread_join(thread_core_id, NULL); 450 | 451 | return 0; 452 | } 453 | -------------------------------------------------------------------------------- /terminal_monitor.h: -------------------------------------------------------------------------------- 1 | /* 2 | * @Description: terminal_monitor.h 3 | * @Version: 1.0 4 | * @Autor: Ming 5 | * @Date: 2021-01-17 22:40:59 6 | * @LastEditors: Ming 7 | * @LastEditTime: 2021-12-03 21:33:51 8 | */ 9 | #ifndef _MONITOR_H 10 | #define _MONITOR_H 11 | 12 | #define BUFFSIZE 512 13 | #define WAIT_SECOND 1 14 | #define MB 1024 15 | 16 | #define DEBUG 0 17 | 18 | typedef struct _CPU_PACKED { 19 | char name[16]; 20 | unsigned int user; //用户模式 21 | unsigned int nice; //低优先级的用户模式 22 | unsigned int system; //内核模式 23 | unsigned int idle; //空闲处理器时间 24 | } CPU_OCCUPY; 25 | 26 | /*sysinfo系统相关信息的结构体*/ 27 | struct sysinfo info; 28 | 29 | /*主机的状态信息结构体*/ 30 | typedef struct _HOST_STATE { 31 | int hour; 32 | int minute; 33 | double cpu_used; 34 | double mem_used; 35 | } HOST_STATE; 36 | 37 | /*收发数据包结构体*/ 38 | typedef struct _RTX_BYTES { 39 | long int tx_bytes; 40 | long int rx_bytes; 41 | struct timeval rtx_time; 42 | } RTX_BYTES; 43 | 44 | /*网卡设备信息结构体*/ 45 | typedef struct _NET_INTERFACE { 46 | char name[16]; /*网络接口名称*/ 47 | char ip[16]; /*网口IP*/ 48 | double d_speed; /*下行速度*/ 49 | double u_speed; /*上行速度*/ 50 | char mac[13]; /*网口MAC地址*/ 51 | /*上下行速度级别 bit 7~0 52 | *bit[0]=d_speed 53 | *bit[1]=u_speed 54 | *1:MB/s 0:KB/s 55 | */ 56 | unsigned char speed_level; /**/ 57 | RTX_BYTES rtx0_cnt; 58 | RTX_BYTES rtx1_cnt; 59 | struct _NET_INTERFACE *next; /*链表指针*/ 60 | } NET_INTERFACE; 61 | 62 | /** 63 | * @description: 必须先打开sysinfo文件,读取内存和运行时间信息 64 | * @param {*} 65 | * @return {*} 66 | * @author: Ming 67 | */ 68 | void open_sysinfo(); 69 | 70 | /** 71 | * @description: 获取终端运行时间 72 | * @param {int} *hours 73 | * @param {int} *minutes 74 | * @return {*} 75 | * @author: Ming 76 | */ 77 | void get_host_runtime(int *hours, int *minutes); 78 | 79 | /** 80 | * @description: 获取某个时刻的CPU负载 81 | * @param {CPU_OCCUPY} *cpu 82 | * @return {*} 83 | * @author: Ming 84 | */ 85 | void get_cpuoccupy(CPU_OCCUPY *cpu); 86 | 87 | /** 88 | * @description: 计算CPU占用率 89 | * @param {CPU_OCCUPY} *c1 90 | * @param {CPU_OCCUPY} *c2 91 | * @return {*} 92 | * @author: Ming 93 | */ 94 | double cal_occupy(CPU_OCCUPY *c1, CPU_OCCUPY *c2); 95 | 96 | /** 97 | * @description: 获取内存占用率 98 | * @param {double} *mem_used 99 | * @return {*} 100 | */ 101 | void get_mem_usage(double *mem_used); 102 | 103 | /** 104 | * @description: 获取内存占用率 105 | * @param {double} *cpu_used 106 | * @return {*} 107 | * @author: Ming 108 | */ 109 | void get_cpu_usage(double *cpu_used); 110 | 111 | /** 112 | * @description: 打开网络接口设备文件/proc/net/dev 113 | * @param {FILE} * 114 | * @return {*} 115 | */ 116 | void open_netconf(FILE **fd); 117 | 118 | /** 119 | * @description: 获取网卡数量和IP地址 120 | * @param {NET_INTERFACE} * 121 | * @param {int} *n 本机网卡数量 122 | * @return {*} 123 | */ 124 | int get_interface_info(NET_INTERFACE **net, int *n); 125 | 126 | /** 127 | * @description: 显示本机活动网络接口 128 | * @param {NET_INTERFACE} *p_net 129 | * @return {*} 130 | */ 131 | void show_netinterfaces(NET_INTERFACE *p_net, int n); 132 | 133 | /** 134 | * @description: 获取网卡当前时刻的收发包信息 135 | * @param {char} *name 136 | * @param {RTX_BYTES} *rtx 137 | * @return {*} 138 | */ 139 | void get_rtx_bytes(char *name, RTX_BYTES *rtx); 140 | 141 | /** 142 | * @description: rtx结构体拷贝--disable 143 | * @param {RTX_BYTES} *dest 144 | * @param {RTX_BYTES} *src 145 | * @return {*} 146 | */ 147 | void rtx_bytes_copy(RTX_BYTES *dest, RTX_BYTES *src); 148 | 149 | /** 150 | * @description: 计算网卡的上下行网速 151 | * @param {double} *u_speed 152 | * @param {double} *d_speed 153 | * @param {unsignedchar} *level 154 | * @param {RTX_BYTES} *rtx0 155 | * @param {RTX_BYTES} *rtx1 156 | * @return {*} 157 | */ 158 | void cal_netinterface_speed(double *u_speed, double *d_speed, 159 | unsigned char *level, RTX_BYTES *rtx0, 160 | RTX_BYTES *rtx1); 161 | 162 | /** 163 | * @description: 获取主机网卡速度信息 164 | * @param {NET_INTERFACE} *p_net 165 | * @return {*} 166 | */ 167 | void get_network_speed(NET_INTERFACE *p_net); 168 | 169 | /** 170 | * @description: 网络信息监控线程 171 | * @param {*} 172 | * @return {*} 173 | */ 174 | void *thread_net(void *arg); 175 | 176 | /** 177 | * @description: CPU、内存、运行时间监控线程 178 | * @param {*} 179 | * @return {*} 180 | */ 181 | void *thread_core(void *arg); 182 | 183 | #endif --------------------------------------------------------------------------------