如何通过管道立即捕获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;
}
程序完成后,会同时显示输出。但我想在程序执行时立即读取输出。
答案 0 :(得分:8)
<stdio.h>
默认是缓冲的,stdout
是行缓冲的。
将printf("%s", s);
替换为printf("%s\n", s);
(结尾换行符会刷新stdout
缓冲区),或者在fflush(NULL);
之后添加对ping
的调用。
实际上,您的问题与pipe
无关,但管道已缓冲。
您可以执行较低级fork
,dup2
,read
,poll
系统调用并明确管理管道上的缓冲区。然后调用wget
可能很有用。
你可以考虑使用像liboping这样的ICMP ping文件,或者考虑做一个HTTP请求(使用HEAD
程序,或者最好是libcurl;也许是一个简单的HTTP {{1请求就足够了)。作为一般建议,请避免使用popen
或system
分配进程(因为目标计算机上可用的命令可能不同)。
阅读一些优秀的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
刷新,用
char *cmds = "ping -c 3 google.com | awk ' /icmp/ { printf(\"%s\\n\", $0); } '";
FILE *cmd = popen ( cmds, "r" );
它可以自己测试。
其他方法不起作用,因为问题是关于管道刷新,而不是当前进程stdout flush。