想象这样一种情况,我有一台配备了两个网卡的电脑,一个连接到互联网,另一个连接到本地网络,如何使用 C# 检测连接到互联网的 IP?
想象这样一种情况,我有一台配备了两个网卡的电脑,一个连接到互联网,另一个连接到本地网络,如何使用 C# 检测连接到互联网的 IP?
试一下这个:
static IPAddress getInternetIPAddress()
{
try
{
IPAddress[] addresses = Dns.GetHostAddresses(Dns.GetHostName());
IPAddress gateway = IPAddress.Parse(getInternetGateway());
return findMatch(addresses, gateway);
}
catch (FormatException e) { return null; }
}
static string getInternetGateway()
{
using (Process tracert = new Process())
{
ProcessStartInfo startInfo = tracert.StartInfo;
startInfo.FileName = "tracert.exe";
startInfo.Arguments = "-h 1 208.77.188.166"; // www.example.com
startInfo.UseShellExecute = false;
startInfo.RedirectStandardOutput = true;
tracert.Start();
using (StreamReader reader = tracert.StandardOutput)
{
string line = "";
for (int i = 0; i < 9; ++i)
line = reader.ReadLine();
line = line.Trim();
return line.Substring(line.LastIndexOf(' ') + 1);
}
}
}
static IPAddress findMatch(IPAddress[] addresses, IPAddress gateway)
{
byte[] gatewayBytes = gateway.GetAddressBytes();
foreach (IPAddress ip in addresses)
{
byte[] ipBytes = ip.GetAddressBytes();
if (ipBytes[0] == gatewayBytes[0]
&& ipBytes[1] == gatewayBytes[1]
&& ipBytes[2] == gatewayBytes[2])
{
return ip;
}
}
return null;
}
请注意,此实现中的findMatch()
函数依赖于类C匹配。如果要支持类B匹配,请省略对ipBytes[2] == gatewayBytes[2]
的检查。www.example.com
。getInternetIPAddress()
,以展示如何使用其他方法。getInternetGateway()
无法解析网关IP,则更新以捕获FormatException
。(如果网关路由器配置为不响应traceroute请求,则可能会发生这种情况。)我建议使用这段简单的代码,因为tracert
并不总是有效,而whatsmyip.com也不是专门为此设计的:
private void GetIP()
{
WebClient wc = new WebClient();
string strIP = wc.DownloadString("http://checkip.dyndns.org");
strIP = (new Regex(@"\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\b")).Match(strIP).Value;
wc.Dispose();
return strIP;
}
这是我尝试获取默认IPv4地址的方法,而不必求助于DNS或调用像ipconfig和route这样的外部进程命令。希望下一个版本的.Net将提供访问Windows路由表的功能。
public static IPAddress GetDefaultIPv4Address()
{
var adapters = from adapter in NetworkInterface.GetAllNetworkInterfaces()
where adapter.OperationalStatus == OperationalStatus.Up &&
adapter.Supports(NetworkInterfaceComponent.IPv4)
&& adapter.GetIPProperties().GatewayAddresses.Count > 0 &&
adapter.GetIPProperties().GatewayAddresses[0].Address.ToString() != "0.0.0.0"
select adapter;
if (adapters.Count() > 1)
{
throw new ApplicationException("The default IPv4 address could not be determined as there are two interfaces with gateways.");
}
else
{
UnicastIPAddressInformationCollection localIPs = adapters.First().GetIPProperties().UnicastAddresses;
foreach (UnicastIPAddressInformation localIP in localIPs)
{
if (localIP.Address.AddressFamily == AddressFamily.InterNetwork &&
!localIP.Address.ToString().StartsWith(LINK_LOCAL_BLOCK_PREFIX) &&
!IPAddress.IsLoopback(localIP.Address))
{
return localIP.Address;
}
}
}
return null;
}
LINK_LOCAL_BLOCK_PREFIX
吗?它是 "169." 吗? - jocull虽然不是100%准确(有些ISP不会为您提供公共IP地址),但您可以检查IP地址是否在保留用于私有地址的范围内。请参见http://en.wikipedia.org/wiki/Classful_network
这里有一篇可能会有帮助的文章:
以下代码用于检索C#中的“网络接口”。您可以将“网络接口”识别为“网络和拨号连接”:您可以通过使用“开始>设置>网络和拨号连接”来访问它们。 C#没有提供检索此列表的简单方法。
IPGlobalProperties ipProperties = IPGlobalProperties.GetIPGlobalProperties();
Console.WriteLine(ipProperties.HostName);
foreach (NetworkInterface networkCard in NetworkInterface.GetAllNetworkInterfaces())
{
foreach (GatewayIPAddressInformation gatewayAddr in networkCard.GetIPProperties().GatewayAddresses)
{
Console.WriteLine("Information: ");
Console.WriteLine("Interface type: {0}", networkCard.NetworkInterfaceType.ToString());
Console.WriteLine("Name: {0}", networkCard.Name);
Console.WriteLine("Id: {0}", networkCard.Id);
Console.WriteLine("Description: {0}", networkCard.Description);
Console.WriteLine("Gateway address: {0}", gatewayAddr.Address.ToString());
Console.WriteLine("IP: {0}", System.Net.Dns.GetHostByName(System.Net.Dns.GetHostName()).AddressList[0].ToString());
Console.WriteLine("Speed: {0}", networkCard.Speed);
Console.WriteLine("MAC: {0}", networkCard.GetPhysicalAddress().ToString());
}
}
跟我的朋友Lukas Šalkauskas的方向一样,我们写了这段代码:
/* digged, built and (here and there) copied "as is" from web, without paying attention to style.
Please, do not shot us for this.
*/
public static void DisplayIPAddresses()
{
Console.WriteLine("\r\n****************************");
Console.WriteLine(" IPAddresses");
Console.WriteLine("****************************");
StringBuilder sb = new StringBuilder();
// Get a list of all network interfaces (usually one per network card, dialup, and VPN connection)
NetworkInterface[] networkInterfaces = NetworkInterface.GetAllNetworkInterfaces();
foreach (NetworkInterface network in networkInterfaces)
{
if (network.OperationalStatus == OperationalStatus.Up )
{
if (network.NetworkInterfaceType == NetworkInterfaceType.Tunnel) continue;
if (network.NetworkInterfaceType == NetworkInterfaceType.Tunnel) continue;
//GatewayIPAddressInformationCollection GATE = network.GetIPProperties().GatewayAddresses;
// Read the IP configuration for each network
IPInterfaceProperties properties = network.GetIPProperties();
//discard those who do not have a real gateaway
if (properties.GatewayAddresses.Count > 0)
{
bool good = false;
foreach (GatewayIPAddressInformation gInfo in properties.GatewayAddresses)
{
//not a true gateaway (VmWare Lan)
if (!gInfo.Address.ToString().Equals("0.0.0.0"))
{
sb.AppendLine(" GATEAWAY "+ gInfo.Address.ToString());
good = true;
break;
}
}
if (!good)
{
continue;
}
}
else {
continue;
}
// Each network interface may have multiple IP addresses
foreach (IPAddressInformation address in properties.UnicastAddresses)
{
// We're only interested in IPv4 addresses for now
if (address.Address.AddressFamily != AddressFamily.InterNetwork) continue;
// Ignore loopback addresses (e.g., 127.0.0.1)
if (IPAddress.IsLoopback(address.Address)) continue;
if (!address.IsDnsEligible) continue;
if (address.IsTransient) continue;
sb.AppendLine(address.Address.ToString() + " (" + network.Name + ") nType:" + network.NetworkInterfaceType.ToString() );
}
}
}
Console.WriteLine(sb.ToString());
}
这是一个获取系统默认连接到互联网时使用的公共IPv4或IPv6地址的2022实现。它使用 https://www.ipify.org 上当前免费的互联网服务/API 描述。基本上,他们的 API 只返回一个简单的字符串,里面只有你的IP地址。
请注意,我正在使用最新的 .Net SDK 进行构建(Aug '22)。可能需要做一些小的更改才能在旧版本上运行。
代码将会像这样使用:
IPAddress ipv4 = await WanIp.GetV4Async(); // return v4 address or IPAddress.None
IPAddress ipv6 = await WanIp.GetV6Async(); // return v6 address or IPAddress.None
IPAddress ip = await WanIp.GetIpAsync(); // might return either v4 or v6
using System.Net;
using System.Net.Http;
using System.Net.Sockets;
using System.Net.Threading.Tasks;
public class WanIp {
private static readonly HttpClient httpClient = new();
public static async Task<IPAddress> GetV4Async() =>
await GetIpAsync(AddressFamily.InterNetwork);
public static async Task<IPAddress> GetV6Async() =>
await GetIpAsync(AddressFamily.InterNetworkV6);
public static async Task<IPAddress> GetIpAsync(AddressFamily family = AddressFamily.Unspecified) {
var uri = family switch {
AddressFamily.InterNetwork => "https://api.ipify.org",
AddressFamily.InterNetworkV6 => "https://api6.ipify.org",
AddressFamily.Unspecified => "https://api64.ipify.org",
_ => throw new ArgumentOutOfRangeException(nameof(family))
};
IPAddress ip;
try {
var ipString = await httpClient.GetStringAsync(uri);
_ = IPAddress.TryParse(ipString, out ip);
} catch (Exception ex) { // If network down, etc.
ip = IPAddress.None;
// maybe throw an exception here if you like
}
// make sure we get family we asked for, or reply with none
if (family != AddressFamily.Unspecified && ip.AddressFamily != family) ip = IPAddress.None;
return ip;
}