Skip to content

MAC 地址和 IP 地址的区别:为什么定位设备靠 IP 不靠 MAC(Python 实现) ​

面试网络岗的人,十有八九被问过「MAC 地址和 IP 地址有什么区别」。多数人背得出「MAC 是物理地址,IP 是逻辑地址」,再往下问一句就卡壳:既然电脑出厂就烧了 MAC,为什么不能直接用 MAC 上网?为什么服务器日志里只记 IP,从来看不到 MAC?

这两个问题其实是同一件事:MAC 管局域网,IP 管互联网。换公网收发数据时,MAC 根本传不出去,唯一能带出来的是 IP。这篇先把区别讲透,再用 Python 写个小脚本,把「本机 MAC、本机内网 IP、公网出口 IP、归属地」一次性查出来,谁管哪一段,一目了然。

一、两个地址各管一段路 ​

MAC 地址是网卡出厂时烧录的 48 位编号,长这样:3c:7c:3f:12:ab:9e。它的职责是在同一个局域网里找人。你的电脑和路由器说「帮我上网」,靠的就是这个编号:ARP 协议在局域网里喊一声「谁是这个 IP,把 MAC 报上来」,然后数据帧按 MAC 送上门。

IP 地址是网络层地址,职责是在不同的网络之间找人。数据要跨省、跨国,路由器不看 MAC 只看 IP——它手里的路由表是按 IP 段写的,「目的地在哪个网段,下一跳往哪走」。

说白了一个类比:IP 是快递单上的收货地址,写得不具体但能跨城市投递;MAC 是小区里的门牌号,出了小区就没人认。快递包裹到了小区门口,快递员才掏出门牌号找门——对应到网络上,数据包到了目标网段,才靠 MAC 完成最后一跳。

所以「既然有了 IP 为什么还需要 MAC」的答案是:IP 负责远途路由,MAC 负责本地投递,缺一个数据就到不了你家门口。

二、为什么定位设备只能靠 IP ​

这是今天想让你记住的重点。一次正常的 web 请求是这样的:

  1. 你的电脑把数据包从网卡发出去,源 MAC 是自己的,目的 MAC 是网关的;
  2. 经过的第一个路由器就把源 MAC 改成自己,接下来的每一跳都做同样的事——MAC 在每一跳都被换掉;
  3. 到了对端服务器,它看到的请求里,MAC 已经不存在了,只有源 IP 从头到尾没变过。

服务器收到请求后想判断「这是哪来的」,唯一可用的线索就是 IP。IP 又能干什么?运营商分配地址段是按地域来的(联通给东北的、电信给西南的都是一大段一大段分),所以 IP 天生带「地域属性」,查归属地就能知道大概的省份城市。这就是全网所有日志分析、风控、反爬都拿 IP 当身份线索的根本原因——不是不想用 MAC,是 MAC 压根传不过来。

顺带回答两个搜索里高频的问题:

  • MAC 地址是全球唯一的吗? 出厂时理论唯一,但系统层面可以改,虚拟机/路由器也能随便造,macOS 和 Windows 还给无线网卡做 MAC 随机化。所以 MAC 连「设备身份」都算不上稳定证据,更不用说位置了。
  • 怎么查自己电脑的 MAC 和 IP? Windows 用 ipconfig /all,Linux/macOS 用 ifconfig 或 ip addr,都能看到两块内容:IPv4 地址是内网 IP,物理地址(Physical Address / ether)就是 MAC。

三、Python 实现:一次查清本机三大件 ​

下面这个脚本只用标准库,Windows/Linux/macOS 都能跑。它做四件事:查本机内网 IP、查本机 MAC(用 uuid.getnode(),返回的就是网卡 48 位编号)、查公网出口 IP 及其归属地(调 IP9 免费接口 https://ip9.com.cn/get,不传参数返回的就是当前请求方的 IP 和归属地)、最后把「内网 IP 段 vs 公网 IP」对比一下,直观看到 MAC/IP 各管哪一段。

python
#!/usr/bin/env python3
"""查本机 MAC / 内网 IP / 公网出口 IP 与归属地,演示 MAC 与 IP 的职责分工。"""
import json
import socket
import struct
import uuid
import urllib.request

def mac_to_str(n):
    return ":".join(f"{(n >> (8 * i)) & 0xFF:02x}"
                    for i in range(5, -1, -1))

def local_mac():
    return mac_to_str(uuid.getnode())

def local_ips():
    """遍历网卡,取出所有 IPv4 内网地址(含 127.0.0.1 及子网信息)。"""
    out = []
    for info in socket.getaddrinfo(socket.gethostname(), None, socket.AF_INET):
        ip = info[4][0]
        if ip not in out:
            out.append(ip)
    return out

def private_net(ip):
    """判断给定 IP 是否属于局域网/私网保留段(RFC1918 + 回环)。"""
    n = struct.unpack(">I", socket.inet_aton(ip))[0]
    return (n >> 24 == 10            # 10.0.0.0/8
            or n >> 20 == 0xAC1      # 172.16.0.0/12
            or n >> 16 == 0xC0A8     # 192.168.0.0/16
            or ip.startswith("127."))

def public_geo():
    """调 IP9 免费接口查当前出口 IP 的归属地(免注册,60 次/分钟)。"""
    req = urllib.request.Request(
        "https://ip9.com.cn/get",
        headers={"User-Agent": "Mozilla/5.0 (ip9-demo)"},
    )
    with urllib.request.urlopen(req, timeout=8) as r:
        d = json.load(r)
    if d.get("ret") != 200:
        raise RuntimeError(f"接口返回异常: {d}")
    return d.get("data", d)  # 接口返回 ret + data 两层,data 里是归属地字段

if __name__ == "__main__":
    print("本机 MAC(网卡物理地址):", local_mac())
    print("本机内网 IP(局域网用)  :", ", ".join(local_ips()))
    print("这些 IP 全是私网段吗?    :",
          all(private_net(ip) for ip in local_ips()))
    print("--- 公网侧(去往互联网时,出口 IP 由运营商 NAT 分配)---")
    g = public_geo()
    print("公网出口 IP:", g["ip"])
    print("归属地     :", g["country"], g.get("prov", ""), g.get("city", ""),
          "| 运营商:", g.get("isp", ""))
    print("经纬度     :", g.get("lng"), g.get("lat"),
          "(城市中心点,不是设备精确位置)")
    print("内网 IP 和公网 IP 不是同一个,这正是『MAC 局域网内找设备、IP 跨网找设备』的体现。")

跑出来的结果长这样(示例输出):

本机 MAC(网卡物理地址): 3c:7c:3f:12:ab:9e
本机内网 IP(局域网用)  : 192.168.31.45
这些 IP 全是私网段吗?    : True
--- 公网侧(去往互联网时,出口 IP 由运营商 NAT 分配)---
公网出口 IP: 219.142.xx.xx
归属地     : 中国 北京 北京 | 运营商: 电信
经纬度     : 116.4074 39.9042 (城市中心点,不是设备精确位置)

几个细节值得说:uuid.getnode() 在部分虚拟机上会返回随机 MAC,但演示逻辑足够;内网 IP 拿到了,但互联网上的服务器永远看不到它——数据离网时,网关会把源地址 NAT 成公网出口 IP,MAC 在每一跳被替换,内网 IP 只在自家网段里有效。这三个「查不到的中间层」就是 MAC/IP 分工最直观的证明。

四、落到真实业务里意味着什么 ​

日志分析只能信 IP。 任何服务端拿到访客数据,能用于地域统计、风控判断的只有 IP 归属地(国家/省/市/运营商),MAC 和内网 IP 一概不可得。对开发者来说,这就是为什么「怎么定位访客」的答案永远是 IP 归属地接口,而不是别的。

别指望 MAC 做跨网身份识别。 有人想用「设备指纹」记住用户,方法可以,但别从 MAC 入手——浏览器端拿不到其他设备的 MAC,系统级 App 拿到也会撞上 MAC 随机化。要识别同一人的多台设备,业界用的是 IP + UserAgent + 浏览器指纹的组合,IP 仍然是其中唯一稳定的地域锚点。

动态 IP 带来的归属地漂移是正常的。 家庭宽带重启路由器可能换出口 IP,手机流量出口常是省级汇聚点。所以「IP 归属地=精确位置」是误区,它是城市级线索:风控里用来做「异地」判断、营销里用来做地区投放、日志里用来做地域分布,都够用,但别拿去定位街道。

想批量确认一批 IP 的归属地,循环调 https://ip9.com.cn/get?ip=目标IP 就行(支持 IPv4/IPv6,免费版免注册、60 次/分钟/IP),注意自己加限速和本地缓存,别对接口打满额度。

总结 ​

MAC 是出厂编号,只在本网段有效,跨网即被替换;IP 是逻辑地址,全程跟着数据包走,也是互联网上唯一能定位「从哪来」的凭据。面试把这个链条讲清楚——源 MAC 每跳被换、源 IP 始终保留、出口 NAT 让内网地址消失——比背定义有说服力得多。动手跑一遍上面的脚本,把本机的三大件打印出来看一次,这组概念就再也忘不掉了。需要查任意 IP 归属地的时候,直接调 IP9 免费接口(https://ip9.com.cn/get?ip=目标IP,官网 https://www.ip9.com.cn)即可,免注册、支持 IPv4/IPv6。