在c中捕获ping的输出

时间:2013-01-22 06:28:28

标签: c linux pipeline

如何通过管道立即捕获ping命令的输出?

这是我的代码:

int main ()
{
    FILE *cmd = popen ( "ping -c 3 google.com | grep icmp", "r" );//ping google
    char *s = malloc ( sizeof ( char ) * 200 );
    while ( 1 )
    {
            fgets ( s, sizeof ( char )*200, cmd );
            printf ( "%s", s);//show outcome
            if ( strstr ( s, "icmp_req=3" ) != 0 )
                    break;
    }
    pclose ( cmd );
    return 0;
}

程序完成后,会同时显示输出。但我想在程序执行时立即读取输出。

5 个答案:

答案 0 :(得分:8)

<stdio.h>默认是缓冲的,stdout是行缓冲的。

printf("%s", s);替换为printf("%s\n", s);(结尾换行符会刷新stdout缓冲区),或者在fflush(NULL);之后添加对ping的调用。

实际上,您的问题与pipe无关,但管道已缓冲。

您可以执行较低级forkdup2readpoll系统调用并明确管理管道上的缓冲区。然后调用wget可能很有用。

你可以考虑使用像liboping这样的ICMP ping文件,或者考虑做一个HTTP请求(使用HEAD程序,或者最好是libcurl;也许是一个简单的HTTP {{1请求就足够了)。作为一般建议,请避免使用popensystem分配进程(因为目标计算机上可用的命令可能不同)。

阅读一些优秀的Linux编程书,例如http://advancedlinuxprogramming.com/

答案 1 :(得分:6)

这是一个小代码,它使用liboping每秒ping www.xively.com并显示延迟。您可以在ubuntu框上安装liboping静态/动态库文件和头文件,如下所示:sudo apt-get install liboping0 liboping-dev oping

然后使用上面的库(gcc -o test test.c -loping)编译以下程序。并以超级用户(sudo)身份运行可执行文件。

<强> test.c的:

 /*
  * 1. install liboping, e.g. `sudo apt-get install liboping0 liboping-dev oping`
  * 2. Compile with -loping, e.g. `gcc -o test test.c -loping`
  * 3. Execute using sudo as super user, e.g. `sudo ./test`
  */

#include <stdlib.h>
#include <stdio.h>
#include <oping.h>

int main(int argc, char **argv) {
    pingobj_t *ping;
    pingobj_iter_t *iter;

    if ((ping = ping_construct()) == NULL) {
        fprintf(stderr, "ping_construct failed\n");
        return -1;
    }
    printf("ping_construct() success\n");

    if (ping_host_add(ping, "www.xively.com") < 0) {
        const char * errmsg = ping_get_error(ping);
        fprintf(stderr, "ping_host_add(www.xively.com) failed. %s\n", errmsg);
        return -1;
    }
    printf("ping_host_add() success\n");

    while (1) {
        if (ping_send(ping) < 0) {
            fprintf(stderr, "ping_send failed\n");
            return -1;
        }
        printf("ping_send() success\n");

        for (iter = ping_iterator_get(ping); iter != NULL; iter =
                ping_iterator_next(iter)) {
            char hostname[100];
            double latency;
            unsigned int len;

            printf("ping_iterator_get() success\n");
            len = 100;
            ping_iterator_get_info(iter, PING_INFO_HOSTNAME, hostname, &len);
            len = sizeof(double);
            ping_iterator_get_info(iter, PING_INFO_LATENCY, &latency, &len);

            printf("hostname = %s, latency = %f\n", hostname, latency);
        }
        sleep(1);
    }
    printf("exiting...\n");

    ping_destroy( ping );

    return 0;
}

<强>输出:

anurag@anurag-PC:~$ sudo ./test
ping_construct() success
ping_host_add() success
ping_send() success
ping_iterator_get() success
hostname = www.xively.com, latency = 233.666000
ping_send() success
ping_iterator_get() success
hostname = www.xively.com, latency = 234.360000
ping_send() success
ping_iterator_get() success
hostname = www.xively.com, latency = 234.076000
ping_send() success
ping_iterator_get() success
hostname = www.xively.com, latency = 231.761000
ping_send() success
ping_iterator_get() success
hostname = www.xively.com, latency = 235.085000
^C
如果你想从你的linux设备检查互联网连接,如果你的ISP或目标没有阻止ICMP数据包,那么liboping很好。如果这些被阻止,您可以使用某个HTTP库尝试从www.google.com或任何其他网站获取index.html页面并检查是否成功

答案 2 :(得分:1)

您无法立即阅读,并且在执行结束时不会打印。

时显示
  • 填充管道的缓冲区或

  • 管道关闭

您需要修改管道的属性。

答案 3 :(得分:1)

printf("%s", s);替换为printf("%s\n", s);

\n将刷新缓冲区,以便在执行printf命令后立即获得输出,并且您不必等到程序执行停止...

答案 4 :(得分:0)

只需强制换行,然后stdout刷新,用

更改cmd
char *cmds = "ping -c 3 google.com | awk ' /icmp/ { printf(\"%s\\n\", $0); } '";
FILE *cmd = popen ( cmds, "r" );

它可以自己测试。

其他方法不起作用,因为问题是关于管道刷新,而不是当前进程stdout flush。