如何通过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
无关,但管道是缓冲的。
您可以执行较低级别的pipe
, fork
, dup2
, read
系统调用并显式管理管道上的缓冲区。 那么调用poll
可能会有用。
你可以考虑使用一个像libping这样的ICMP ping库,或者考虑使用wget
程序,或者最好使用libcurl ;或许一个简单的HTTP HEAD
请求就足够了。 作为一般性建议,避免使用popen
或system
分叉进程(因为目标计算机上可用的命令可能不相同)。
阅读一些很好的Linux编程书籍,如http://advancedlinuxprogramming.com/
这是一个小代码,它使用liboping每秒钟 ping http://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, 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刷新。