我正在尝试使用C获取自己的ip地址。 想法是获取“ifconfig”的输出,将其放在.txt文件中并提取inet和inet6值。 我尝试在.txt文件中写入ifconfig输出:
#include <stdio.h>
#include <stdlib.h>
#include <string>
int main ()
{
char command[1000];
strcpy(command, "ifconfig");
system(command);
FILE *fp = fopen("textFile.txt", "ab+");
//... how to write the output of 'system(command)' in the textFile.txt?
fclose(fp);
//... how to scraping a file .text in C ???
return 0;
}
感谢您的任何帮助和建议, 斯特凡诺
答案 0 :(得分:0)
您实际上希望使用系统调用来完成此操作 - 而不是运行ifconfig命令。
Linux上有一个类似的问题:using C code to get same info as ifconfig
(因为ifconfig是一个Linux命令,我假设你在问Linux)。
一般要点是使用ioctl()
系统调用。
否则,您将要求您的进程将其拆分为两个,从子输出到父输入创建一个管道,并在子节点上调用exec以将其替换为“ifconfig”。然后,如果你想从中获得任何有用的东西,你将不得不解析它。
答案 1 :(得分:0)
在Linux中,使用man 7 netdevice
描述了您可以使用的界面,Anish Goyal已经回答。
这非常简单和强大,并且使用非常少的资源(因为它只是一些系统调用)。不幸的是,它是特定于Linux的,并且使代码不可移植。
可以便携地这样做。我在这里描述了可移植选项,因为特定于Linux的选项相当简单。虽然这种方法对于获取本地主机IP地址非常复杂,但该模式通常非常有用,因为它可以隐藏特定于系统的怪癖,同时可以轻松地允许系统管理员自定义行为。
可移植解决方案的想法是使用小帮助程序或shell脚本来获取信息,并以一些易于解析的格式将信息输出到主程序。如果您的应用程序名为yourapp
,则通常会在/usr/lib/yourapp/
中安装此类帮助程序,例如/usr/lib/yourapp/local-ip-addresses
。
就个人而言,我建议使用shell脚本(以便系统管理员可以在需要自定义行为时轻松编辑帮助程序),以及每个接口在其自己的行上的输出格式,由空格分隔的字段,也许
inet interface-name ipv4-address [hostname] *
inet6 interface-name ipv6-address [hostname] *
即。第一个令牌指定地址系列,第二个令牌指定接口名称,第三个指定地址,可选地后跟与该地址对应的主机名或别名。
关于帮助程序/ shell脚本本身,有两种基本方法:
单次
例如,解析Linux中的LANG=C LC_ALL=C ip address
输出。
打印地址后,程序/脚本将退出。
连续
程序/脚本将打印ip地址信息,但是只要管道保持打开状态,它就会运行,而不是退出,如果接口被取下或出现,它将提供更新。
在Linux中,程序/脚本可以使用DBUS或NetworkManager来等待此类事件;它不需要轮询(即重复检查命令输出)。
shell脚本具有额外的好处,它可以同时支持多个发行版,甚至操作系统(至少跨POSIX系统)。这些脚本通常有类似的大纲:
#!/bin/sh
export LANG=C LC_ALL=C
case "$(uname -s)" in
Linux)
if [ -x /bin/ip ]; then
/bin/ip -o address | awk \
'/^[0-9]*:/ {
addr = $4
sub(/\/.*$/, "", addr)
printf "%s %s %s\n", $3, $2, addr
}'
exit 0
elif [ -x /sbin/ifconfig ]; then
/sbin/ifconfig | awk \
'BEGIN {
RS = "[\t\v\f\r ]*\n"
FS = "[\t\v\f ]+"
}
/^[0-9A-Za-z]/ {
iface = $1
}
/^[\t\v\f ]/ {
if (length(iface) > 0)
for (i = 1; i < NF-1; i++)
if ($i == "inet") {
addr = $(i+1)
sub(/^addr:/, "", addr)
printf "inet %s %s\n", iface, addr
} else
if ($i == "inet6") {
addr = $(i+2)
sub(/\/.*$/, "", addr)
printf "inet6 %s %s\n", iface, addr
}
}'
exit 0
fi
;;
# Other systems?
esac
printf 'Cannot determine local IP addresses!\n'
exit 1
该脚本将语言环境设置为C
/ POSIX
,以便外部命令的输出将采用默认语言环境(英语等)。 uname -s
提供内核名称(Linux的Linux
),并且可以使用例如Linux进行进一步的检查。 [
shell命令。
我只为Linux实现了scriptlet,因为那是我现在所使用的机器。 (ip
和ifconfig
备选方案都可以在我的机器上运行,并提供相同的输出 - 尽管您不能指望按任何特定顺序获取接口。)
系统管理员可能需要编辑此特定帮助程序脚本的情况包括尚未支持的系统,具有新核心工具的系统以及具有应从正常接口列表中排除的接口的系统(例如,连接到为特权目的保留的内部子网,如DNS,文件服务器,备份,LDAP等)。
在C应用程序中,您只需使用popen("/usr/lib/yourapp/local-ip-addresses", "r")
执行外部程序或shell脚本,它会为您提供一个FILE *
,您可以将其视为文件(除非您无法搜索或快退)它)。从管道中读取所有内容后,pclose()
句柄:
#define _POSIX_C_SOURCE 200809L
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
/* ... */
FILE *in;
char *line_ptr = NULL;
size_t line_size = 0;
ssize_t line_len;
int status;
in = popen("/usr/lib/myapp/local-ip-addresses", "r");
if (!in) {
fprintf(stderr, "Cannot determine local IP addresses: %s.\n", strerror(errno));
exit(EXIT_FAILURE);
}
while (1) {
line_len = getline(&line_ptr, &line_size, in);
if (line_len < 1)
break;
/* Parse line_ptr */
}
free(line_ptr);
line_ptr = NULL;
line_size = 0;
if (ferror(in) || !feof(in)) {
pclose(in);
fprintf(stderr, "Read error while obtaining local IP addresses.\n");
exit(EXIT_FAILURE);
}
status = pclose(in);
if (!WIFEXITED(status) || WEXITSTATUS(status)) {
fprintf(stderr, "Helper utility /usr/lib/myapp/local-ip-addresses failed to obtain local IP addresses.\n");
exit(EXIT_FAILURE);
}
我省略了解析代码,因为有很多选择 - strtok()
,sscanf()
,甚至是将行拆分为标记的自定义函数(并填充指针数组) - 我自己喜欢的选项是最不受欢迎的选项(最后一个,自定义函数)。
虽然完成此任务所需的代码几乎不值得,但使用此方法的应用程序往往会使用其中的几个帮助程序。然后,当然,以允许轻松解析的方式选择管道数据格式是有意义的,但支持所有用例。那么摊销成本也更容易接受。