在c中捕获ping的输出

如何通过pipe道直接捕获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; } 

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

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

替换你的printf("%s", s);printf("%s\n", s); (结尾的换行符将刷新stdout缓冲区)或添加一个调用fflush(NULL); 就在它之后。

实际上,你的问题与ping无关,但管道是缓冲的。

您可以执行较低级别的pipeforkdup2read系统调用并显式管理管道上的缓冲区。 那么调用poll可能会有用。

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

阅读一些很好的Linux编程书籍,如http://advancedlinuxprogramming.com/

这是一个小代码,它使用liboping每秒钟 ping http://www.xively.com并显示延迟&#x3002; 你可以在你的Ubuntu机器上安装liboping静态/动态库文件和头文件,如下所示: sudo apt-get install liboping0 liboping-dev oping

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

test.c的:

  /* * 1. install liboping, eg `sudo apt-get install liboping0 liboping-dev oping` * 2. Compile with -loping, eg `gcc -o test test.c -loping` * 3. Execute using sudo as super user, eg `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"); 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数据包,libbing是很好的。 如果这些被阻止,您可以使用一些HTTP库来尝试从www.google.com或任何其他网站获取index.html页面,并检查是否成功

你不能立即阅读它,并且在执行结束时不打印。

这是显示的时刻

  • 管道的缓冲区被填满或

  • 管道关闭

您需要修改管道的属性。

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

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

只需强制换行输出,然后stdout ,更改cmd

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

它工作,由我自己测试。

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