C# 获取本机IP地址的方法文档

概述

本文档整理了在C#中获取本机IP地址的多种方法,涵盖了从简单到复杂的各种场景,包括获取单个IP地址、所有网络接口信息、IPv4/IPv6地址筛选等。

方法列表

方法一:使用 Dns.GetHostEntry()(简单通用)

using System;
using System.Net;
using System.Net.Sockets;

public static string GetLocalIPAddress()
{
    var host = Dns.GetHostEntry(Dns.GetHostName());
    foreach (var ip in host.AddressList)
    {
        if (ip.AddressFamily == AddressFamily.InterNetwork)
        {
            return ip.ToString();
        }
    }
    throw new Exception("No network adapters with an IPv4 address in the system!");
}

特点: - 简单易用 - 返回第一个找到的IPv4地址 - 可能返回127.0.0.1(回环地址)


方法二:使用 NetworkInterface(推荐 - 最精确)

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

public static string GetLocalIPAddress()
{
    // 获取所有活动的网络接口
    var networkInterfaces = NetworkInterface.GetAllNetworkInterfaces()
        .Where(n => n.OperationalStatus == OperationalStatus.Up &&
                   n.NetworkInterfaceType != NetworkInterfaceType.Loopback);

    foreach (var networkInterface in networkInterfaces)
    {
        // 获取IP配置信息
        var ipProperties = networkInterface.GetIPProperties();

        // 获取IPv4地址
        var ipv4Address = ipProperties.UnicastAddresses
            .FirstOrDefault(addr => addr.Address.AddressFamily == AddressFamily.InterNetwork);

        if (ipv4Address != null)
        {
            return ipv4Address.Address.ToString();
        }
    }

    return "No IPv4 address found";
}

特点: - 精确控制网络接口 - 可筛选活动接口和排除回环接口 - 提供完整的网络接口信息


方法三:使用 Socket 连接外部地址

using System.Net;
using System.Net.Sockets;

public static string GetLocalIPAddress()
{
    using (Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, 0))
    {
        socket.Connect("8.8.8.8", 65530); // 连接Google的DNS服务器
        IPEndPoint endPoint = socket.LocalEndPoint as IPEndPoint;
        return endPoint.Address.ToString();
    }
}

特点: - 通过实际连接获取本地出口IP - 适用于NAT环境 - 需要外部网络连接


方法四:获取所有IP地址(完整信息)

using System.Net;
using System.Net.NetworkInformation;
using System.Net.Sockets;
using System.Collections.Generic;

public class NetworkInfo
{
    public static List<string> GetAllIPAddresses()
    {
        List<string> ipAddresses = new List<string>();
        var host = Dns.GetHostEntry(Dns.GetHostName());

        foreach (var ip in host.AddressList)
        {
            ipAddresses.Add($"{ip.AddressFamily}: {ip}");
        }

        return ipAddresses;
    }

    public static void DisplayNetworkInfo()
    {
        var networkInterfaces = NetworkInterface.GetAllNetworkInterfaces();

        foreach (var ni in networkInterfaces)
        {
            Console.WriteLine($"接口名称: {ni.Name}");
            Console.WriteLine($"描述: {ni.Description}");
            Console.WriteLine($"状态: {ni.OperationalStatus}");
            Console.WriteLine($"类型: {ni.NetworkInterfaceType}");

            var ipProperties = ni.GetIPProperties();
            foreach (var ip in ipProperties.UnicastAddresses)
            {
                Console.WriteLine($"  IP地址: {ip.Address} ({ip.Address.AddressFamily})");
                Console.WriteLine($"  子网掩码: {ip.IPv4Mask}");
            }
            Console.WriteLine("---");
        }
    }
}

方法五:异步版本

using System.Net;
using System.Net.NetworkInformation;
using System.Net.Sockets;
using System.Threading.Tasks;

public static async Task<string> GetLocalIPAddressAsync()
{
    var hostEntry = await Dns.GetHostEntryAsync(Dns.GetHostName());

    foreach (var ip in hostEntry.AddressList)
    {
        if (ip.AddressFamily == AddressFamily.InterNetwork)
        {
            return ip.ToString();
        }
    }

    return "No IPv4 address found";
}

实用工具类

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

public static class NetworkHelper
{
    // 获取本机IPv4地址(优先获取非内网地址)
    public static string GetLocalIPv4()
    {
        try
        {
            var addresses = Dns.GetHostAddresses(Dns.GetHostName())
                .Where(ip => ip.AddressFamily == AddressFamily.InterNetwork &&
                            !IPAddress.IsLoopback(ip) &&
                            !IsInternalIP(ip))
                .Select(ip => ip.ToString())
                .ToList();

            return addresses.FirstOrDefault() ?? "127.0.0.1";
        }
        catch
        {
            return "127.0.0.1";
        }
    }

    // 判断是否为内网IP
    private static bool IsInternalIP(IPAddress ip)
    {
        byte[] bytes = ip.GetAddressBytes();

        // 10.0.0.0/8
        if (bytes[0] == 10) return true;

        // 172.16.0.0/12
        if (bytes[0] == 172 && bytes[1] >= 16 && bytes[1] <= 31) return true;

        // 192.168.0.0/16
        if (bytes[0] == 192 && bytes[1] == 168) return true;

        // 169.254.0.0/16 (APIPA)
        if (bytes[0] == 169 && bytes[1] == 254) return true;

        return false;
    }

    // 获取指定网络接口的IP
    public static string GetIPByInterface(string interfaceName)
    {
        var networkInterface = NetworkInterface.GetAllNetworkInterfaces()
            .FirstOrDefault(ni => ni.Name.Equals(interfaceName, StringComparison.OrdinalIgnoreCase));

        if (networkInterface != null)
        {
            var ipProperties = networkInterface.GetIPProperties();
            var ipv4Address = ipProperties.UnicastAddresses
                .FirstOrDefault(addr => addr.Address.AddressFamily == AddressFamily.InterNetwork);

            return ipv4Address?.Address.ToString() ?? "Not found";
        }

        return "Interface not found";
    }
}

使用示例

class Program
{
    static void Main()
    {
        // 获取本机IPv4地址
        Console.WriteLine($"本机IPv4地址: {NetworkHelper.GetLocalIPv4()}");

        // 获取所有网络接口信息
        var interfaces = NetworkInterface.GetAllNetworkInterfaces();
        foreach (var ni in interfaces)
        {
            if (ni.OperationalStatus == OperationalStatus.Up)
            {
                Console.WriteLine($"{ni.Name}: {NetworkHelper.GetIPByInterface(ni.Name)}");
            }
        }
    }
}

注意事项

1. 网络接口状态

  • 建议只获取状态为 OperationalStatus.Up 的接口
  • 排除回环接口 (NetworkInterfaceType.Loopback)

2. IP地址类型

  • IPv4AddressFamily.InterNetwork
  • IPv6AddressFamily.InterNetworkV6
  • 根据实际需求选择合适的地址类型

3. 异常处理

网络操作可能因以下原因失败: - 无网络连接 - 权限不足 - DNS解析失败

建议添加适当的异常处理机制。

4. 多网卡环境

机器可能有多个网络接口卡(NIC),每个NIC可能有多个IP地址: - 有线网卡 - 无线网卡 - 虚拟网卡(VMware、VirtualBox等) - VPN虚拟网卡

5. 内网IP地址范围

常见内网IP地址段: - 10.0.0.0/8 (10.0.0.0 - 10.255.255.255) - 172.16.0.0/12 (172.16.0.0 - 172.31.255.255) - 192.168.0.0/16 (192.168.0.0 - 192.168.255.255) - 169.254.0.0/16 (APIPA,自动私有IP寻址)

6. 特殊地址

  • 127.0.0.1:本地回环地址
  • 0.0.0.0:任意地址
  • 255.255.255.255:广播地址

性能考虑

  1. 缓存结果:频繁获取IP地址时可考虑缓存
  2. 异步操作:避免阻塞UI线程,使用异步方法
  3. 最小权限:应用程序应以最小必要权限运行

推荐方案

场景 推荐方法 理由
快速获取IP 方法一(Dns.GetHostEntry) 简单快速,适用于大多数场景
精确控制 方法二(NetworkInterface) 可筛选接口,信息完整
获取出口IP 方法三(Socket连接) 适用于NAT环境
完整网络信息 方法四(NetworkInterface) 获取所有接口详细信息
异步应用 方法五(异步版本) 避免阻塞,提高响应性

总结

在C#中获取本机IP地址有多种方法,选择哪种方法取决于具体需求:

  1. 简单场景:使用方法一
  2. 精确控制:使用方法二(推荐)
  3. 特殊需求:根据实际情况选择其他方法

建议在生产环境中使用方法二,因为它提供了最准确和完整的网络接口信息,能够处理复杂的网络环境。


文档版本:1.0
最后更新:2023年10月
适用框架:.NET Framework 4.5+ / .NET Core 2.0+ / .NET 5+