zoukankan      html  css  js  c++  java
  • 编程获取本机IPv4及IPv6地址

    首先,我要通过编程直接获取,而不是去读诸如ifconfig等命令的输出。

    其实是只想获取IPv6地址的,不过我猜想它们差不多,也确实看到不少相关搜索结果,于是顺带着看了。

    首先,使用gethostbyname查自己通常是不行的,因为可能得到127.0.0.1,而且我猜,这样不能处理拥有多个IPv4地址的情况。另外一种方式是连上某个主机,然后调用getsockname。这样需要能够直接连上那个主机,好处是如果有多个网络接口,这样可以知道到底走的是哪个接口,调试网络时不错。我最满意的方案在这里,使用ioctl来获取。这个方法可以获取指定网络接口的IPv4地址。至于有哪些网络接口嘛,直接读/proc/net/dev吧。

    1
    2
    3
    4
    5
    6
    7
    8
    import fcntl
    import socket
    import struct
    ifname = b'eth0'
    s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    # 0x8915 是 SIOCGIFADDR
    ip = socket.inet_ntoa(fcntl.ioctl(s.fileno(), 0x8915, struct.pack('256s', ifname[:15]))[20:24])
    print(ip)

    然而,这样只能获取IPv4地址。创建个AF_INET6的 socket 传过去会报错「Inappropriate ioctl for device」。那怎么办呢?Google 没找到,我去搜了下内核源码。inet_ioctl里有对SIOCGIFADDR的处理。但是,inet6_ioctl里却没有了。

    于是,我只好去下载ifconfig所属的 net-tools 的源码,找到相关代码:

    lib/interface.c (部分)
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    #if HAVE_AFINET6
        /* FIXME: should be integrated into interface.c.   */
     
        if ((f = fopen(_PATH_PROCNET_IFINET6, "r")) != NULL) {
        while (fscanf(f, "%4s%4s%4s%4s%4s%4s%4s%4s %08x %02x %02x %02x %20s\n",
                  addr6p[0], addr6p[1], addr6p[2], addr6p[3],
                  addr6p[4], addr6p[5], addr6p[6], addr6p[7],
              &if_idx, &plen, &scope, &dad_status, devname) != EOF) {
            if (!strcmp(devname, ptr->name)) {
            sprintf(addr6, "%s:%s:%s:%s:%s:%s:%s:%s",
                addr6p[0], addr6p[1], addr6p[2], addr6p[3],
                addr6p[4], addr6p[5], addr6p[6], addr6p[7]);

    这里就是ifconfig输出IPv6部分的代码了。可以看到它打开了一个奇怪的文件。跟过去,发现是

    1
    #define _PATH_PROCNET_IFINET6       "/proc/net/if_inet6"

    囧,这个文件我早就发现过了的。看来和IPv4的情况不同,IPv6地址只能通过/proc里的文件获取了。而且输出成人可读格式不容易(ifconfig是自己实现的)。

    PS: 我还发现了件好玩的事,在 Linux 源码的include/linux/sockios.h中,SIOCGIFINDEX中的字母 C 写漏了。通过git blame我发现,这个拼写错误在至少七年前 Linux 内核代码迁移到 git 前就修正了。Linus Torvalds 说之前的代码导入到 git 后有 3.2GB。我不得不承认这是个无比正确的决定,因为现在的.git已经有600多兆了,git 不支持断点续传,clone 下来已经很不容易了。

    另外,我还联想到了 Unix 系统调用中的creat,以及 HTTP 协议中的referer :D

    1
    2
    #define SIOCGIFINDEX    0x8933      /* name -> if_index mapping */
    #define SIOGIFINDEX SIOCGIFINDEX    /* misprint compatibility :-)  
  • 相关阅读:
    打印九九乘法表
    PAT (Basic Level) Practice (中文) 1091 N-自守数 (15分)
    PAT (Basic Level) Practice (中文)1090 危险品装箱 (25分) (单身狗进阶版 使用map+ vector+数组标记)
    PAT (Basic Level) Practice (中文) 1088 三人行 (20分)
    PAT (Basic Level) Practice (中文) 1087 有多少不同的值 (20分)
    PAT (Basic Level) Practice (中文)1086 就不告诉你 (15分)
    PAT (Basic Level) Practice (中文) 1085 PAT单位排行 (25分) (map搜索+set排序+并列进行排行)
    PAT (Basic Level) Practice (中文) 1083 是否存在相等的差 (20分)
    PAT (Basic Level) Practice (中文) 1082 射击比赛 (20分)
    PAT (Basic Level) Practice (中文) 1081 检查密码 (15分)
  • 原文地址:https://www.cnblogs.com/shihao/p/2701111.html
Copyright © 2011-2022 走看看