• 编程获取本机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 :-)  
  • 相关阅读:
    grafana 使用技巧
    好书推荐之Mysql三剑客 :《高性能Mysql》、《Mysql技术内幕》、《数据库索引设计与优化》
    从中间件团队窃取了这个组件,见识到了编码能力的天花板!!
    好书推荐之《深入理解计算机系统》
    好书推荐之《Java 核心技术:卷 1 基础知识》
    好书推荐之《码出高效》、《阿里巴巴JAVA开发手册》
    好书推荐之JAVA并发编程扛鼎之作:《Java并发编程实战》、《Java并发编程的艺术》
    深入理解并发编程同步工具类
    好书推荐之《深入理解JAVA虚拟机》
    状态机的技术选型看这篇就够了,最后一个直叫好!!!
  • 原文地址:https://www.cnblogs.com/shihao/p/2701111.html
Copyright © 2020-2023  润新知