how to get the updated result continuously by using popen command in c language?
ProgrammingThis forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.
Notices
Welcome to LinuxQuestions.org, a friendly and active Linux Community.
You are currently viewing LQ as a guest. By joining our community you will have the ability to post topics, receive our newsletter, use the advanced search, subscribe to threads and access many other special features. Registration is quick, simple and absolutely free. Join our community today!
Note that registered members see fewer ads, and ContentLink is completely disabled once you log in.
If you have any problems with the registration process or your account login, please contact us. If you need to reset your password, click here.
Having a problem logging in? Please visit this page to clear all LQ-related cookies.
Get a virtual cloud desktop with the Linux distro that you want in less than five minutes with Shells! With over 10 pre-installed distros to choose from, the worry-free installation life is here! Whether you are a digital nomad or just looking for flexibility, Shells can put your Linux machine on the device that you want to use.
Exclusive for LQ members, get up to 45% off per month. Click here for more info.
how to get the updated result continuously by using popen command in c language?
I'm now doing a project regarding the link traffic. In my project i try to use popen command to get the number of bytes i received in c programming and i successfully did so.
However here comes my problem, when i want to process the data I obtained, I found that this command keep giving me the same value without updating it. Here I post the code i roughly did in order to process the data.
Code:
#include <stdio.h>
#include <stdlib.h> /* required for atoi */
long int calculate();
main()
{
long int a[3];
long int b[5];
int i,j;
for (j=0; j<5; j++)
{
b[j]=0;
for(i=0 ; i<3; i++)
{
a[i]=calculate();
b[j]+= a[i];
}
b[j]=b[j]/3;
printf("The number of bytes is: %d\n", b[j]);
}
}
long int calculate()
{
FILE *fp;
char line[130]; /* line of easa!from unix command*/
int i;
fp = popen("ifconfig eth0 |grep bytes|cut -c20-35", "r"); /* Issue the command. */
/* Read a line */
while ( fgets( line, sizeof line, fp))
{
printf("%s", line); /* %s means string */
i = atoi(line);
}
pclose(fp);
return i;
}
Does anyone please help me figure out my problems or correct me if there is error on my code since i still a newbie to c language and linux world.
I looked at your code and couldn't see any mistake. The reason for identical reads may be the speed which the loop is executed. Another reason could be traffic on the network.
I would suggest you to use "atol" instead of "atoi" for the conversion of the read values and also declare the variable "i" as long into the "calculate" function. However, I don't think this is the problem.
Tried you program, got a couple of warnings from gcc's "-Wall" option, fixed them. And it worked.
As Osvaldo already pointed out, your loop is running full speed. So there is probably little netwerk traffic within each loop iteration. Also your program will use max load on your CPU. That said, when I tried it while downloading a linux kernel source I did see increasing numbers, even inside the inner loop. Note that it depends on the download speeds.
Anyway, I addded a one-second delay within the inner loop. I also changed the command line, so it does not use 'ifconfig' to read and parse the /prov/net/dev file. IMHO it would be better to do the entire reading and parsing of /proc/net/dev inside the C-program, avoiding running a external command with popen to do that.
Code:
#include <stdio.h>
#include <stdlib.h> /* required for atoi() */
#include <unistd.h> /* required for sleep() */
long int calculate();
int main()
{
long int a[3];
long int b[5];
int i, j;
for (j = 0; j < 5; j++) {
b[j] = 0;
for (i = 0; i < 3; i++) {
a[i] = calculate();
b[j] += a[i];
sleep(1); /* one second delay */
}
b[j] = b[j] / 3;
printf("The number of bytes is: %ld\n", b[j]); /* %ld for long int */
}
return 0;
}
long int calculate()
{
FILE *fp;
char line[130];
long int i;
fp = popen("sed -n 's/^ *eth0:\\([0-9]*\\).*/\\1/p' /proc/net/dev", "r");
while (fgets(line, sizeof line, fp)) {
printf("%s", line); /* %s means string */
i = atol(line); /* convert to long int instead of int */
}
pclose(fp);
return i;
}
sorry for my late reply and thanks osvaldomarques and Hko for your precious opinion.
I'll try to understand how the new command "sed" (for me,) works.
btw, does anyone please explain to me the following?
Quote:
so it does not use 'ifconfig' to read and parse the /prov/net/dev file. IMHO it would be better to do the entire reading and parsing of /proc/net/dev inside the C-program, avoiding running a external command with popen to do that.
i not really understand the meaning of "parse" and what is the /prov/net/dev file? Where is the file located? why it is better to use the command "sed" than "popen"?
sorry for my late reply and thanks osvaldomarques and Hko for your precious opinion.
I'll try to understand how the new command "sed" (for me,) works.
btw, does anyone please explain to me the following?
i not really understand the meaning of "parse" and what is the /prov/net/dev file? Where is the file located? why it is better to use the command "sed" than "popen"?
sorry for my silly question
The file is /proc/net/dev (not /prov/...).
What Hko was stating was that you should consider opening the /proc/net/dev file, and reading it line by line until you find the desired network interface (e.g. eth0), then continue to parse that same line to obtain the number of bytes received on that interface.
Whether this is more efficient or not is really not an issue if you decide to idle for a second or more waiting for the data (bytes received) to be updated.
int main() { FILE* fp = fopen("/proc/net/dev", "r");
if (fp) { int lineNumForEth0 = 0;
for (;;) { char line[256] = {0};
if (lineNumForEth0 == 0) { // search for the line that contains eth0 data while (fgets(line, sizeof(line), fp)) { ++lineNumForEth0;
if (strstr(line, "eth0")) { break; } } } else { // skip ahead now that we know where eth0 is located at for (int i = 0; i < lineNumForEth0; ++i) fgets(line, sizeof(line), fp); }
thanks for your reply, it's very helpful. And from the reply from you all, i just know that not only can get the number of bytes received from ifconfig but can get from /proc/net/dev file as well.
Btw, about the source code from Hko, i can't get the received signal bytes.
What i get is just 0. I not really understand the sed command
This is so because in C backslashes in string constants are used for newlines ("\n"), tabs ("\t") and so on. So to have a single backslash in a C string constant you need two of them.
About the sed command: sed edits text according to "regular expressions" ('grep' also uses regular expressions). By default sed outputs all lines of text it reads, whether sed has changed it or not. The -n option tells sed to output a line only when a 'p' command applies (the last 'p' in the sed command I posted).
The sed-command s/this/that/p" means:
If a line matches with this (a regular expression, a text-pattern), then substitute it with that. (the 's' in 's/../../' stands for "substitute")
And if the substitution happened, print the changed line to stdout (because of the 'p' in 's/../../p', which only makes sense in combination with the -n option. See above).
And we want sed to print this line if it is about eth0, and replace the entire line with only the digits sed finds right after "eth0:".
The text-pattern "this" to match was:
Code:
^ *eth0:\([0-9]*\).*
'^' means: start of the line
<space> followed by '*' means: any number of spaces.
'eth0:' means just 'eth0:'.
'[0-9]*' means: any number of digit characters (0,1,2,3...9)
'.*' means: any number of any character. So this matches all the rest of the line we are not interested in. This is needed because we want the 's/../../' command to replace (substitute) the entire line.
Note that the digits part of the regular expression pattern ('[0-9]*') is between '\(' and '\)'. That means sed should "remember" that part.
The second part of the s/../../ command ("that") will replace the line of text if the pattern ("this") matches. This is simply: '\1' which means: the matched part of the line of text between the first pair of '\(' and '\)'.
I found it difficult to explain how sed works. But I hope it he1ps a bit. Play with sed, it can be very handy sometimes.
To find some sed tutorials google for something like "sed tutorial regexp".
My preferred way to read the number of bytes recieved on a network interface would be to do the enitre job in C itself. That is without any external programs like sed or ifconfig-grep-cut. Personally I feel if I run command lines from C I'm on the wrong track and should have made a shell script instead of creating a C program ;-)
In this case, it is even quite easy and the code gets even simpler to understand without the sed/cut/grep/ifconfig stuff.
Something like this:
Code:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#define PROCFILE "/proc/net/dev"
long int get_received_bytes();
int main()
{
long int a[3];
long int b[5];
int i, j;
for (j = 0; j < 5; j++) {
b[j] = 0;
for (i = 0; i < 3; i++) {
a[i] = get_received_bytes("eth0");
b[j] += a[i];
sleep(1); /* one second delay */
}
b[j] = b[j] / 3;
printf("The number of bytes is: %ld\n", b[j]);
}
return 0;
}
long int get_received_bytes(const char *device)
{
FILE *fp;
char line[130];
char *numstr;
if ((fp = fopen(PROCFILE, "r")) == NULL) {
perror("Could not open" PROCFILE);
return 0L;
}
while (fgets(line, sizeof line, fp) != NULL) {
if ((numstr = strstr(line, device)) != NULL) {
numstr += strlen(device) + 1; /* +1 to skip the colon (:) */
return atol(numstr);
}
}
fclose(fp);
return 0L;
}
Thanks a lot. After you explain part by part about the sed command, I understand a lot. However, although this command display the number of bytes received in the terminal, but when I compiled the C program, it gives me warning "unknown escape sequence '\)'". Can you please explain to me what's the problem?
Actually i encountered this problem as well when i write this program like in my 1st post. At first, my terminal command is
it successfully displayed the number of received bytes. But when i tried to compile using gcc, it can't recognise the space in the command cut -d" " -f1
After that i only changed to command
Code:
ifconfig eth0 |grep bytes|cut -c20-35
since atoi() command will ignore the extra alphabet.
but when I compiled the C program, it gives me warning "unknown escape sequence '\)'". Can you please explain to me what's the problem?
You forgot to double the backslash before the ')'. Also when I tried it again, I noticed I still had a bug in the sed command: In /proc.net/dev there are (somtimes?) space between 'eth0:' and the digits so in the regular expression there need to be added another <space>* combination. These were not matched in the code I posted. (thought I had tested it, but seems not to e true..)
So, one more time :-)
Code:
# in the shell:
bash$ sed -n 's/^ *eth0: *\([0-9]*\).*/\1/p' /proc/net/dev
it successfully displayed the number of received bytes. But when i tried to compile using gcc, it can't recognise the space in the command cut -d" " -f1
Right. That is because C uses double quotes around strings. In C, you can put two string constants after eachother and the compiler will paste (concatenate) them together.
This:
Code:
printf("Hello" "World");
is exactly the same as:
Code:
printf("HelloWorld");
So to have double quotes inside a string in C, you need to escape them with a backslash to prevent the C compiler to 'see' them:
Yeah~~ Thanks Hko. But this also let me knows that there is still a long way for me to master C. I'll strive to improve my knowledge about C. Thanks everyone
LinuxQuestions.org is looking for people interested in writing
Editorials, Articles, Reviews, and more. If you'd like to contribute
content, let us know.