【发布时间】:2021-06-03 04:01:25
【问题描述】:
我正在尝试用 C 语言编写一个脚本,它从文件 /proc/net/dev 中读取带宽信息并对其进行处理以产生每秒上传和下载流量。
文件如下所示:
Inter-| Receive | Transmit
face |bytes packets errs drop fifo frame compressed multicast|bytes packets errs drop fifo colls carrier compressed
lo: 4845 60 0 0 0 0 0 0 4845 60 0 0 0 0 0 0
enp3s0: 197557966 217836 0 0 0 0 0 591 21516707 160167 0 0 0 0 0 0
sit0: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
我在两个网络之间切换(另一个网络当前未在文件中列出),因此我将网络设备的名称作为参数。
目前enp3s0 是我从中获取网络信息的设备。
现在我遇到的问题是当我尝试使用 sscanf 处理所需的行时。
出于某种原因,sscanf 总是为我从中读取的各种值生成乱码输出。
所以我制作了一个单独的测试文件,在其中我直接将这一行声明为一个字符串,并使用几乎完全相同的逻辑,它可以完美地按预期工作。
主文件:
注意:在故障排除过程中,某些行已被注释掉。 有些行仅用于详细输出。 另外字节转换部分还是留下来了,因为遇到这个问题,我没有再进一步。
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#define NETWORK_FILE "/proc/net/dev"
//==========================FUNC_DECL
unsigned long * receive(FILE *,char*);
char *searchstr(FILE *,char *);
//===========================TYPE-STRING
typedef char *String;
//===========================FUNCTIONS
// The function that looks for argv[1] in the NETWORK_FILE and returns the line as char *.
char *searchstr(FILE *ndev,char *netid){
int found=0,lineno=1;
char tmpf[600];
//GETTING THE LINE MATCH
while(fgets(tmpf,sizeof(tmpf),ndev) != NULL){
if(strstr(tmpf,netid) != NULL) {
printf("Device %s Found on Line %d",netid,lineno);
found++;
break;
}
lineno++;
}
if (found==0){ printf("ERROR!::NO_NET_DEVICE::No such device exists as %s\n",netid); }
char *line = tmpf;
if(line == NULL){ printf("ERROR!:SEARCHSTR_NULL_LINE_RET: Empty Line being sent for parsing"); exit(2);}
return line;
}
//The function that sends Upload and Download bytes to the Main function in an array ptr form.. sort of
unsigned long * receive(FILE *dev,char *netname) {
unsigned int dspeed=0,uspeed=0,dump;
unsigned long rcv1,rcv2,trv1,trv2;
char *n_line = (char *)malloc(200*sizeof(char));
char *drop =(char *) malloc(15*sizeof(char));
n_line = searchstr(dev,netname);
if(n_line == NULL){ printf("Error!: No Line received for parsing"); }
printf("\n Line Input is: \n%s",n_line);
//--------THIS IS THE MAIN LINE WHERE THE PROBLEM IS. THE LINE BELOW IT IS THE ONE I WROTE TO TROUBLESHOOT
/*sscanf(n_line,"%s %lu %u %u %u %u %u %u %u %lu %u %u %u %u %u %u %u",drop,&rcv1,&dump,&dump,&dump,&dump,&dump,&dump,&dump,&trv1,&dump,&dump,&dump,&dump,&dump,&dump,&dump);*/
sscanf(n_line,"%s%lu",drop,&rcv1);
printf("\nDrop is read as: \t %s\nRx is %lu",drop,rcv1);
if(rcv1 == 0){ printf("\nError!:NULL_VALUE-RX-1: Value received for parsing is 0."); }
sleep(1);
sscanf(n_line,"%s %lu %u %u %u %u %u %u %u %lu %u %u %u %u %u %u %u", drop,&rcv2,&dump,&dump,&dump,&dump,&dump,&dump,&dump,&trv2,&dump,&dump,&dump,&dump,&dump,&dump,&dump);
if(rcv2 == 0){ printf("Error!:NULL_VALUE-RX-2: Value received for parsing is 0."); }
dspeed = rcv2-rcv1;
uspeed = trv2-trv1;
unsigned long *speeds [2];
speeds[0] = &dspeed;
speeds[1] = &uspeed;
return *speeds;
}
//==========================Main
int main(int argc,char *argv[]) {
FILE *netdev;
String networkid = malloc(10);
networkid=argv[1];
netdev = fopen(NETWORK_FILE,"r");
if (netdev == NULL) { printf("Error Opening file!"); return (-1); }
unsigned long *spd[2];
*spd = receive(netdev,networkid);
printf("\n D: %lu | U: %lu \n",*spd[0],*spd[1]);
fclose(netdev);
}
测试文件:
注意:测试文件的值稍旧,因为它使用的是旧的复制粘贴。
#include <stdio.h>
#include <stdlib.h>
int main(int argc,char *argv[]) {
char *w1,*w2,*w3,*w4,*w5;
w1 = (char*) malloc(8*sizeof(char));
w2 = (char*) malloc(8*sizeof(char));
w3 = (char*) malloc(8*sizeof(char));
w4 = (char*) malloc(8*sizeof(char));
w5 = (char*) malloc(15*sizeof(char));
unsigned long n1,n2,d1,d2,d3,d4,d5,d6,d7;
char *teststring,*devstring;
devstring = (char *) malloc(150*sizeof(char));
devstring = "enp3s0: 168010376 192508 0 0 0 0 0 547 19528703 142230 0 0 0 0 0 0";
sscanf(devstring,"%s %lu",w5,&d1);
printf("\n\nDev line parse is:\n %s RX: %lu\n",w5,d1);
}
输出
主文件
Device enp3s0 Found on Line 4
Line Input is:
enp3s0: 197678794 218123 0 0 0 0 0 617 21694353 160864 0 0 0 0 0 0
Drop is read as: <= There is usually gibberish here. Its different everytime. And sometimes its not there at all
Rx is 94544931811891
D: 94544931811891
测试文件
Dev line parse is:
enp3s0: RX: 168010376
我几乎是 C 的初学者(这是我第一个使用指针的程序。我仍然无法理解这些)所以肯定会以可以想象的最糟糕/愚蠢的方式做一些事情。请随时纠正我。
编辑:
所以根据@Mathieu 的回答,我尝试为 sscanf 合并退货检查:
int assign_count = sscanf(n_line,"%s %lu %*u %*u %*u %*u %*u %*u %*u %lu %*u %*u %*u %*u %*u %*u %*u",drop,&rcv1,&trv1);
if(assign_count == 3){
printf("\nRx is %lu",rcv1);
}else { printf("\nERROR!::RECEIVE_ASSIGN_FAILURE:: Failed to assign %d values(Current: %d)",3,assign_count); }
输出: 这会随机给我两个不同的输出。
Device enp3s0 Found on Line 4
Line Input is:
enp3s0: 201330925 226694 0 0 0 0 0 790 23566091 172240 0 0 0 0 0 0
ERROR!::RECEIVE_ASSIGN_FAILURE:: Failed to assign 3 values(Current: -1)
D: 93951710999123
Device enp3s0 Found on Line 4
Line Input is:
enp3s0: 201339561 226756 0 0 0 0 0 798 23586994 172381 0 0 0 0 0 0
ERROR!::RECEIVE_ASSIGN_FAILURE:: Failed to assign 3 values(Current: 2)
Error!:NULL_VALUE-RX-1: Value received for parsing is 0.Error!:NULL_VALUE-RX-2: Value received for parsing is 0.
D: 0
在一种情况下,ret 或 assign_count 显示为 -1,另一种情况下显示为 2。在某些执行过程中,我也随机遇到 Segmentation Fault。
【问题讨论】:
-
你应该检查
sscanf返回的值,它会告诉你已经进行了多少转换,那么你可以读取哪些字段 -
如果您需要忽略一次转换,请使用
%*d,而不是存储在dump中 -
等等我不这样做吗?输出
Drop is read as:和Rx is中的行是我用来检查sscanf 提供的值的。或者您是说 sscanf 有一种方法可以实际显示我的输入字符串的默认格式? -
char *line =(char *) malloc(sizeof(tmpf)); line = tmpf;毫无意义。您分配空间,然后丢弃对它的唯一引用。 -
在
line = tmpf之后,line持有一个地址,该地址在函数返回后无效。您需要strcpy(或类似名称)而不是作业。