导读:本期聚焦于小伙伴创作的《如何用C#正确获取本机IPv4地址?详解常见代码案例与坑点》,敬请观看详情。在写桌面或服务端程序时,经常需要拿到本机真实可用的IPv4地址,但不少代码会顺带返回虚拟机网卡、回环地址或IPv6结果。从NetworkInterface的底层筛选逻辑看,只有先排除非启用状态和回环接口,再遍历单播地址族为InterNetwork的项,才能稳定拿到物理网卡地址。本文对比了Dns.GetHostAddresses与NetworkInterface两种思路,指出前者容易混入无效地址,并给出可直接复用的完整方法,同时说明多网卡环境下如何按优先级挑选。

在C#开发中,获取本机IPv4地址是一个常见需求,比如做本地服务绑定、局域网通信或设备标识时都要用到。如果不加筛选地直接读取系统网络信息,很容易拿到回环地址、虚拟机虚拟网卡地址或者IPv6地址,导致业务逻辑出错。

如何用C#正确获取本机IPv4地址?详解常见代码案例与坑点

为什么不能直接用Dns类获取

很多初学者会优先想到使用Dns.GetHostAddresses方法,通过本机主机名解析出所有绑定的IP。这种做法代码简短,但隐患明显:它返回的是所有地址族的结果,而且会包含127.0.0.1这类回环地址,也可能包含IPv6地址,甚至在某些配置了多个网络服务的机器上返回顺序并不稳定。

下面的代码演示了这种简单但不够严谨的写法:

using System;
using System.Net;

class Program
{
    static void Main()
    {
        string hostName = Dns.GetHostName();
        IPAddress[] addresses = Dns.GetHostAddresses(hostName);
        foreach (IPAddress addr in addresses)
        {
            Console.WriteLine(addr.ToString());
        }
    }
}

运行后你可能会看到类似::1、fe80::开头的IPv6地址,以及127.0.0.1。若业务只支持IPv4且需要真实网卡地址,就必须额外过滤,而Dns类本身并不提供网卡状态等信息,过滤起来并不方便。

使用NetworkInterface精准筛选IPv4

更可靠的方案是基于System.Net.NetworkInformation.NetworkInterface来枚举网络接口。其核心原理是:先判断网卡是否处于Up状态、不是回环接口,再读取该接口的单播地址集合,挑出地址族为InterNetwork的项。这样能自然排除禁用网卡、虚拟回环和IPv6。

以下方法展示了完整的获取逻辑,并增加了对虚拟网卡名称的常见排除策略:

using System;
using System.Net;
using System.Net.NetworkInformation;
using System.Linq;

class IpHelper
{
    public static string GetLocalIPv4()
    {
        // 获取所有网络接口
        var interfaces = NetworkInterface.GetAllNetworkInterfaces();
        foreach (var ni in interfaces)
        {
            // 只处理已启用且非回环的网卡
            if (ni.OperationalStatus != OperationalStatus.Up)
                continue;
            if (ni.NetworkInterfaceType == NetworkInterfaceType.Loopback)
                continue;

            // 遍历单播地址
            var props = ni.GetIPProperties();
            foreach (var ua in props.UnicastAddresses)
            {
                if (ua.Address.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork)
                {
                    // 排除常见虚拟网卡(如VMware、VirtualBox)
                    if (ni.Description.IndexOf("Virtual", StringComparison.OrdinalIgnoreCase) >= 0)
                        continue;
                    return ua.Address.ToString();
                }
            }
        }
        return "127.0.0.1";
    }
}

上面代码通过OperationalStatus.Up确保网卡在用,用NetworkInterfaceType.Loopback排除回环,再用AddressFamily.InterNetwork锁定IPv4。对于装有虚拟机的开发机,增加Description关键字排除可以进一步提升准确率。

这种方式的优点是信息维度丰富,不仅能拿到地址,还能知道子网掩码、网关等;缺点是实现比Dns略长,且在多网卡环境下可能需按优先级(如有线优先于无线)进一步排序。

多网卡环境下的选取策略

当设备同时连着有线、无线和VPN时,简单返回第一个匹配项可能拿到不期望的网段。可以通过给接口类型加权来优化,例如优先选Ethernet,其次Wireless,最后其他。

示例改进如下:

using System;
using System.Net;
using System.Net.NetworkInformation;

class IpHelper
{
    public static string GetBestLocalIPv4()
    {
        string fallback = "127.0.0.1";
        var list = NetworkInterface.GetAllNetworkInterfaces()
            .Where(n => n.OperationalStatus == OperationalStatus.Up &&
                         n.NetworkInterfaceType != NetworkInterfaceType.Loopback)
            .ToList();

        // 按类型优先级排序
        list.Sort((a, b) => GetWeight(a).CompareTo(GetWeight(b)));
        foreach (var ni in list)
        {
            foreach (var ua in ni.GetIPProperties().UnicastAddresses)
            {
                if (ua.Address.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork)
                    return ua.Address.ToString();
            }
        }
        return fallback;
    }

    static int GetWeight(NetworkInterface ni)
    {
        if (ni.NetworkInterfaceType == NetworkInterfaceType.Ethernet) return 1;
        if (ni.NetworkInterfaceType == NetworkInterfaceType.Wireless80211) return 2;
        return 3;
    }
}

通过权重排序,程序会优先返回有线网络的IPv4,更符合大多数服务端和桌面程序的预期。若你的场景需要特定网段,也可以结合IPAddress的网段比对来做二次过滤。

总体来看,使用NetworkInterface并配合状态、类型与地址族过滤,是C#中获取本机IPv4最稳妥的做法。相比Dns解析,它逻辑清晰、可控性强,也便于应对复杂的网络环境。

C#IPv4本机IP修改时间:2026-08-08 16:36:28

免责声明:​ 已尽一切努力确保本网站所含信息的准确性。网站内容多为原创整理与精心编撰,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们处理。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。