【问题标题】:How to append "ifconfig" in a file .txt in C language?如何在 C 语言的文件 .txt 中附加“ifconfig”?
【发布时间】:2017-03-21 15:40:00
【问题描述】:

我正在尝试使用 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;
}

感谢您的任何帮助和建议, 斯特凡诺

【问题讨论】:

  • 假设你使用的是linux,看看stackoverflow.com/questions/2283494/…
  • 再一次,假设您使用的是 Linux,请查看C: Run a System Command and Get Output?。您还需要检查原件,了解任何新内容。
  • 您希望它如何与 DHCP/zeroconf 一起使用? XY 问题。要么从您的界面或其他可移植方式获取 IP。
  • 是的,Ubuntu 16.04。谢谢。
  • 我怀疑屏幕抓取标签不属于这里。只是一个高级建议..一旦您以编程方式确定了获取接口 IP 地址的方法,就没有必要将其写入文件,然后从该文件中读取以进行解析。一旦你得到它,只需在内存中进行解析,如果你仍然想这样做,将信息写入文件。

标签: c ip screen-scraping fopen ifconfig


【解决方案1】:

您实际上希望使用系统调用来完成此操作 - 而不是运行 ifconfig 命令。

这里有一个针对 Linux 的类似问题:using C code to get same info as ifconfig

(因为 ifconfig 是一个 Linux 命令,我假设你问的是 Linux)。

一般要点是使用ioctl() 系统调用。

否则,您将分叉您的进程以将其拆分为两个,创建从子进程的输出到父进程的输入的管道,并在子进程上调用 exec 以将其替换为“ifconfig”。然后,如果您想从中获得任何有用的信息,则必须解析该字符串。

【讨论】:

    【解决方案2】:

    在 Linux 中,使用 man 7 netdevice 描述您可以使用的接口,因为 Anish Goyal 已经回答。

    这是非常简单和健壮的,并且使用很少的资源(因为它只是几个系统调用)。不幸的是,它是特定于 Linux 的,并且使代码不可移植。

    可以便携地执行此操作。我在这里描述了可移植选项,因为特定于 Linux 的选项相当微不足道。尽管仅获取本地主机 IP 地址的方法相当复杂,但该模式非常有用,因为它可以隐藏特定于系统的怪癖,同时允许系统管理员轻松自定义行为。

    可移植解决方案的想法是,您使用一个小的帮助程序或 shell 脚本来获取信息,并让它以某种易于解析的格式将信息输出到您的主程序。如果您的应用程序被命名为yourapp,则通常在/usr/lib/yourapp/ 中安装此类帮助程序,例如/usr/lib/yourapp/local-ip-addresses。

    就我个人而言,我建议使用 shell 脚本(以便系统管理员可以在需要自定义行为时轻松编辑帮助程序)和输出格式,其中每个接口都在自己的行上,字段用空格分隔,也许

    inet 接口名称 ipv4 地址 [ 主机名 ]*
    inet6 接口名称 ipv6 地址 [ 主机名 ]*

    即第一个记号指定地址族,第二个记号指定接口名称,第三个记号指定地址,可选地后跟与该地址对应的主机名或别名。

    对于辅助程序/shell脚本本身,有两种基本的做法:

    1. 一次性

      例如,在 Linux 中解析 LANG=C LC_ALL=C ip address 输出。 打印地址后程序/脚本将退出。

    2. 连续

      程序/脚本将打印 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),并且可以使用例如[ 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(),甚至是一个将行拆分为标记(并填充指针数组)的自定义函数——还有我自己的首选option 是最不受欢迎的一个(最后一个,自定义函数)。

    虽然仅此任务所需的代码几乎不值得花时间,但使用这种方法的应用程序往往会使用几个这样的帮助程序。然后,当然,以一种易于解析但支持所有用例的方式选择管道数据格式是有意义的。摊余成本也更容易接受。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-11-05
      • 1970-01-01
      • 2010-10-02
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多