一直在买VPS,但是对于网络的质量监测却从来也没在意过。这次想动手搭建一个简单的监测系统。

架构很简单

架构.png

获取被监测节点到目标IP的Ping丢包率,然后通过tcp socket的方式传给web站点,由web站点的服务处理入库,最终以web页面的方式展示出来。

被监测节点到web站点之间用kcptun通讯,这种方式使用UDP快速,另外我不会加密tcp socket,直接用kcptun来做加密了。

第一步就是如何获取Ping的丢包结果

ping -c 1000 -f 8.8.8.8 | awk 'NR==4 {print $6}'

-c 指定Ping包的数量
-f 使用最快的方式发包
NR==4 获取第4行
{print $6} 此例中awk命令以空格或TAB键来分隔字符串,{print $6}表示打印分隔后的第6组数据

之后会得到一个带%的结果:0.9%

第二步就是如何通过C语言来获取这样的结果

因为ping是一个已经存在系统中的命令,首先想到使用exec系列的函数,但是后面的awk怎么处理呢?又会涉及到子进程,父进程之间通信的问题。两个简单的命令暂时不想这么复杂。

通过搜索,找到了popen函数 参考:C语言popen()函数:建立管道I/O,于是就可以写成

#include <stdio.h>
int main()
{
    FILE * fp;
    char buffer[5];
    fp = popen("ping -c 1000 -f 8.8.8.8 | awk 'NR==4 {print $6}'", "r");
    fgets(buffer, sizeof(buffer), fp);
    printf("%s", buffer);
    pclose(fp);    
    return 0;
}

加上-std=c11编译之后会出错warning: implicit declaration of function ‘popen’,原因是popen is not part of C,解决方法,加上#define _GNU_SOURCE 详见Why does -std=c11 with gcc hide popen in stdio.h?

#define _GNU_SOURCE
#include <stdio.h>
int main()
{
    FILE * fp;
    char buffer[5];
    fp = popen("ping -c 1000 -f 8.8.8.8 | awk 'NR==4 {print $6}'", "r");
    fgets(buffer, sizeof(buffer), fp);
    printf("%s", buffer);
    pclose(fp);    
    return 0;
}

输出0.9%

第三步,需要把%去掉,使用strtok_r函数

#define _GNU_SOURCE
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main()
{
    FILE * fp;
    char buffer[5];
    // 函数原型 char *strtok_r(char *str, const char *delim, char **saveptr);
    const char * const delim = "%";  // 分隔符
    char *saveptr = NULL;
    char *substr = NULL;

    fp = popen("ping -c 1000 -f 8.8.8.8 | awk 'NR==4 {print $6}'", "r");
    fgets(buffer, sizeof(buffer), fp);
    pclose(fp);
    printf("%s\n",buffer);
    substr = strtok_r(buffer, delim, &saveptr);
    printf("%s\n",substr);    
    return 0;
}

输出0.9,但是这里的数值只是字符串类型的,还需要转成真正的数值

第四步,将string形式的数值转成intfloat形式,参考:Converting Strings to Numbers in C/C++

#define _GNU_SOURCE
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main()
{
    FILE * fp;
    char buffer[5];
    float result;

    // strtok_r 相关
    const char * const delim = "%";  // 分隔符
    char *saveptr = NULL;
    char *substr = NULL;

    fp = popen("ping -c 1000 -f 8.8.8.8 | awk 'NR==4 {print $6}'", "r");
    fgets(buffer, sizeof(buffer), fp);
    pclose(fp);

    // 以 % 分隔字符串
    substr = strtok_r(buffer, delim, &saveptr);

    // 将string类型数值转成float类型
    sscanf(substr, "%f", &result);
    printf("\nThe value of x : %0.1f\n", result); // 0.1 保留1位小数
    return 0;
}

输出0.9


通过以上四步,在C语言中获取Ping的丢包率,并以float类型输出结果

标签: none

评论已关闭