V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
推荐学习书目
Learn Python the Hard Way
Python Sites
PyPI - Python Package Index
http://diveintopython.org/toc/index.html
Pocoo
值得关注的项目
PyPy
Celery
Jinja2
Read the Docs
gevent
pyenv
virtualenv
Stackless Python
Beautiful Soup
结巴中文分词
Green Unicorn
Sentry
Shovel
Pyflakes
pytest
Python 编程
pep8 Checker
Styles
PEP 8
Google Python Style Guide
Code Style from The Hitchhiker's Guide
starsky007
V2EX  ›  Python

搬运一段 Python 获取局域网 IP 的方法,十分优雅!

  •  
  •   starsky007 · 2021-10-19 20:27:28 +08:00 · 5626 次点击
    这是一个创建于 1123 天前的主题,其中的信息可能已经有所发展或是发生改变。

    代码

    获取局域网 IP,一般做法是先枚举网卡、再获取 IP,但是这种做法的缺点是,不够便携,在不同的机器上需要不同的配置,代码实现上也比较啰嗦。这里搬运一段来自 Stack Overflow 的代码,适用性强、十分优雅。使用 Python 实现,我也就发在 Python 节点了,其他语言也可以借鉴。

    import socket
    def get_ip():
        s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        try:
            # doesn't even have to be reachable
            s.connect(('10.255.255.255', 1))
            IP = s.getsockname()[0]
        except Exception:
            IP = '127.0.0.1'
        finally:
            s.close()
        return IP
    

    来源: networking - Finding local IP addresses using Python's stdlib - Stack Overflow

    应用场景

    比如,DDNS 客户端,如果想要为局域网 IP 绑定域名,往往需要人工选择网卡或者正则表达式匹配域名,我见过的几个 DDNS 客户端比如 No-IP Dynamic Update ClientNewFuture/DDNS 都是这么做的,一般 DDNS 客户端则不支持使用局域网 IP 。如果使用上述代码或思路,就可以方便获取局域网 IP 、简化程序设计、简化用户配置。

    27 条回复    2021-11-09 15:52:28 +08:00
    proxytoworld
        1
    proxytoworld  
       2021-10-19 21:41:21 +08:00
    这是适用于 网卡和外头连接的,如果有几个网卡,那些网卡不和外界连接的话就没办法了,这个获取本机 IP 的实现在 mirai 木马里面有
    starsky007
        2
    starsky007  
    OP
       2021-10-19 21:49:09 +08:00
    @proxytoworld
    我看原帖里有提到“Works even if all interfaces are unplugged from the network”,即使没有外网连接,也能获取默认路由 IP 。
    adoal
        3
    adoal  
       2021-10-19 22:04:44 +08:00
    “不够便携”……机翻的?
    starsky007
        4
    starsky007  
    OP
       2021-10-19 22:16:44 +08:00
    @adoal
    只有代码是搬运的,其他是我自己写的。protable/便携,意思是,不同环境下只需要配置一次;表达可能有点生硬,您有什么建议?
    princelai
        5
    princelai  
       2021-10-19 22:33:03 +08:00 via Android
    @starsky007 结合上下文,不能在别的机器上用,应该翻译成不便移植更好吧
    chenqh
        6
    chenqh  
       2021-10-19 23:58:43 +08:00   ❤️ 1
    这个东西好像不对,如果用了 vpn 的话

    PS D:\ccode\HelloWorld> & C:/Users/Lenovo/AppData/Local/Microsoft/WindowsApps/python3.8.exe d:/ccode/HelloWorld/local.py
    10.110.110.122
    PS D:\ccode\HelloWorld> & C:/Users/Lenovo/AppData/Local/Microsoft/WindowsApps/python3.8.exe d:/ccode/HelloWorld/local.py
    192.168.50.235
    dangyuluo
        7
    dangyuluo  
       2021-10-20 00:08:32 +08:00
    @princelai 现在社会步伐这么快,谁有空来翻译地信雅达
    dingwen07
        8
    dingwen07  
       2021-10-20 00:25:58 +08:00 via iPhone
    socket.gethostbyname(socket.gethostname())
    dingwen07
        9
    dingwen07  
       2021-10-20 00:26:31 +08:00 via iPhone
    #8 盲猜的,没试过
    kokutou
        10
    kokutou  
       2021-10-20 04:39:56 +08:00 via Android   ❤️ 4
    局域网 IP❎
    默认路由 IP✅
    raysonx
        11
    raysonx  
       2021-10-20 04:47:17 +08:00 via iPad
    IPv4 only 的。。。。
    skinny
        12
    skinny  
       2021-10-20 08:03:27 +08:00
    10.255.255.255 换成任意 IP 结果也是一样的
    starsky007
        13
    starsky007  
    OP
       2021-10-20 09:31:43 +08:00
    @princelai
    “可移植”一般指的是二进制文件在不同操作系统平台上能运行。
    starsky007
        14
    starsky007  
    OP
       2021-10-20 09:52:28 +08:00
    @chenqh
    好问题。准确地说,代码不是获取局域网 IP,而是获取具有默认路由的本地 IP 。
    starsky007
        15
    starsky007  
    OP
       2021-10-20 09:53:49 +08:00
    @dingwen07
    原帖里其他回答也说了你说的这种写法,是不一样的。
    starsky007
        16
    starsky007  
    OP
       2021-10-20 09:54:26 +08:00
    @kokutou
    👍
    starsky007
        17
    starsky007  
    OP
       2021-10-20 10:03:15 +08:00
    @skinny
    原帖里说了为什么要用 10.255.255.255 ,有差别。
    starsky007
        18
    starsky007  
    OP
       2021-10-20 10:08:12 +08:00
    还是要看一下原帖,帖子只是搬运代码、加了一点点自己的评论,并没有把原帖里面的讨论全部翻译过来。
    ungrown
        19
    ungrown  
       2021-10-20 10:33:20 +08:00   ❤️ 1
    @dangyuluo #7 咱也没必要转进到“信达雅”吧,再说“便携”其实挺信达雅的。
    把 portable 这个词用来指代“轻便性”、“自适应性”、“可移植性”或者“自带运行环境无需额外安装”,本来就是类似于比喻的修辞用法,大家觉得这个词表达效果很精妙所以变成了常用语。
    portable 的精髓就是讲究一个“随遇而安”,借用“便携”的表意来表达这份“随意性”、“轻便性”,倒并非刻意指代“移植”,所以直接按照字面意思来翻译就挺好。
    ungrown
        20
    ungrown  
       2021-10-20 10:37:53 +08:00
    我觉得这个函数的局限性还是应该体现在这个帖子的标题当中的,那就是用它写回答的人所表达的那样:它只能获取到设备的“主”IP 地址(也就是附带默认路由的那个地址),而并不能列出所有网络接口上的地址。
    Wincer
        21
    Wincer  
       2021-10-20 10:42:07 +08:00
    试试 psutil 这个库
    starsky007
        22
    starsky007  
    OP
       2021-10-20 11:34:47 +08:00
    @ungrown
    @Wincer
    需求不就是方便快捷地获取默认主 IP 吗?
    julyclyde
        23
    julyclyde  
       2021-10-20 12:16:24 +08:00
    我们这里都是用 magic number 8915 的,嘿嘿
    然后到 mac 上就不行了
    exiaohao
        24
    exiaohao  
       2021-10-20 12:24:17 +08:00
    这个面对大多数情况应该是够了吧,而且是挺巧妙的
    但是如果对 10.255.255.255 这个地址 有什么策略路由或者走的网卡不一样可能会有不一样的结果?赶脚还能用来探测不同地址的不同路由 hh
    skinny
        25
    skinny  
       2021-10-20 13:37:40 +08:00
    @starsky007 原帖说的是广播地址就可以,因为程序不能直接使用广播地址。并不是说一定要 10.255.255.255
    ZeroDu
        26
    ZeroDu  
       2021-10-21 09:57:11 +08:00
    这个不错,在 java 里面怎么实现?
    vanton
        27
    vanton  
       2021-11-09 15:52:28 +08:00
    本地目录装个 psutil ,然后直接用 psutil.net_if_addrs() 不就得了。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2683 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 25ms · UTC 01:55 · PVG 09:55 · LAX 17:55 · JFK 20:55
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.