How can I capture the output of ping command via pipeline immediately ?
Here is my code:
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;
}
When the program finished, it will show the output at the same time. But I would like to read the output immediately while the program execute.
<stdio.h>
is buffered by default, and stdout
is line-buffered.
Replace your printf("%s", s);
with printf("%s\n", s);
(the ending newline would flush the stdout
buffer) or add a call to fflush(NULL);
just after it.
Actually, your question is unrelated to ping
, but the pipe is buffered.
You might do the lower level pipe
, fork
, dup2
, read
syscalls and manage explicitly the buffer on the pipe. Then calling poll
could be useful.
You could consider using a ICMP pinging library like liboping or consider instead doing an HTTP request (either using the wget
program, or preferably libcurl; perhaps a simple HTTP HEAD
request could be enough). As a general advice avoid forking a process with popen
or system
(because the commands available might not be the same on the target computer).
Read some good Linux programming book, like http://advancedlinuxprogramming.com/
Here is a small code that uses liboping to ping www.xively.com every second and display the latency. You can install liboping static/dynamic library files and header files on your ubuntu box like so: sudo apt-get install liboping0 liboping-dev oping
Then compile the following program with the above library (gcc -o test test.c -loping
). And run the executable as a super user (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;
}
Output:
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
liboping is good if you want to check for internet connectivity from your linux device provided your ISP or target does not block ICMP packets. If these are blocked, you can use some HTTP library to try and fetch the index.html page from www.google.com or any other website and check if that succeeds
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With