C# 获取默认网关
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/13634868/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Get the Default Gateway
提问by Frecklefoot
I'm writing a program that shows the user their IP address, Subnet mask and Default gateway. I can get the first two, but for the last one, this is what I turned up:
我正在编写一个程序,向用户显示他们的 IP 地址、子网掩码和默认网关。我可以得到前两个,但对于最后一个,这就是我发现的:
GatewayIPAddressInformationCollection gwc =
System.Net.NetworkInformation.NetworkInterface.GetAllNetworkInterfaces()[0].GetIPProperties().GatewayAddresses;
That, of course, returns a collection of GatewayIPAddressInformation. So, if a computer has multiple gateways, how can I determine which is the defaultgateway?
当然,这会返回GatewayIPAddressInformation. 那么,如果一台计算机有多个网关,我如何确定哪个是默认网关?
In practice, I've only ever seen this collection contain a single entry, but since it's implemented as a collection, it stands to reason that some computers contain multiple gateways, none of which are marked as "Default". So is there a way to determine the defaultor is it all just guesswork?
在实践中,我只见过这个集合包含一个条目,但由于它是作为一个集合实现的,所以有些计算机包含多个网关是理所当然的,没有一个网关被标记为“默认”。那么有没有办法确定默认值还是只是猜测?
采纳答案by caesay
It should be the first valid and enabled gateway address of the first enabled network interface:
它应该是第一个启用的网络接口的第一个有效且启用的网关地址:
public static IPAddress GetDefaultGateway()
{
return NetworkInterface
.GetAllNetworkInterfaces()
.Where(n => n.OperationalStatus == OperationalStatus.Up)
.Where(n => n.NetworkInterfaceType != NetworkInterfaceType.Loopback)
.SelectMany(n => n.GetIPProperties()?.GatewayAddresses)
.Select(g => g?.Address)
.Where(a => a != null)
// .Where(a => a.AddressFamily == AddressFamily.InterNetwork)
// .Where(a => Array.FindIndex(a.GetAddressBytes(), b => b != 0) >= 0)
.FirstOrDefault();
}
I've also added some further commented checks which have been pointed out as useful by other people here. You can check the AddressFamilyone to distinguish between IPv4 and IPv6. The latter one can be used if you're having issues with a 0.0.0.0address being returned.
我还添加了一些进一步评论的检查,这里的其他人指出这些检查很有用。您可以选中AddressFamily一项以区分 IPv4 和 IPv6。如果您在0.0.0.0返回地址时遇到问题,则可以使用后一个。
That said, the recommended way to do this uses GetBestInterfaceto find an interface for routing to a specific IP address. If you have a destination IP address in mind already, then it's better to use this - and so I've also included an example of that below:
也就是说,推荐的执行此操作的方法GetBestInterface是查找用于路由到特定 IP 地址的接口。如果您已经有目标 IP 地址,那么最好使用它 - 因此我还在下面提供了一个示例:
[DllImport("iphlpapi.dll", CharSet = CharSet.Auto)]
private static extern int GetBestInterface(UInt32 destAddr, out UInt32 bestIfIndex);
public static IPAddress GetGatewayForDestination(IPAddress destinationAddress)
{
UInt32 destaddr = BitConverter.ToUInt32(destinationAddress.GetAddressBytes(), 0);
uint interfaceIndex;
int result = GetBestInterface(destaddr, out interfaceIndex);
if (result != 0)
throw new Win32Exception(result);
foreach (var ni in NetworkInterface.GetAllNetworkInterfaces())
{
var niprops = ni.GetIPProperties();
if (niprops == null)
continue;
var gateway = niprops.GatewayAddresses?.FirstOrDefault()?.Address;
if (gateway == null)
continue;
if (ni.Supports(NetworkInterfaceComponent.IPv4))
{
var v4props = niprops.GetIPv4Properties();
if (v4props == null)
continue;
if (v4props.Index == interfaceIndex)
return gateway;
}
if (ni.Supports(NetworkInterfaceComponent.IPv6))
{
var v6props = niprops.GetIPv6Properties();
if (v6props == null)
continue;
if (v6props.Index == interfaceIndex)
return gateway;
}
}
return null;
}
回答by Falcon313
I think that you should iterate over this collection and show all the Gateways, since if there are many gateways to an adapter they are all considered Default to that adapter
我认为你应该遍历这个集合并显示所有网关,因为如果有很多网关到一个适配器,它们都被认为是该适配器的默认值
回答by Code Jockey
I know this is a slightly older question but, I had just come upon the need to retrieve the IPV4 address of the local gateway. The accepted answer doesn't quite fit the bill when it comes to my own system so, I modified it to suite and I'm sure others will be able to use this solution, too.
我知道这是一个稍微旧的问题,但是,我刚刚发现需要检索本地网关的 IPV4 地址。当涉及到我自己的系统时,接受的答案并不完全符合要求,因此,我将其修改为套件,并且我相信其他人也将能够使用此解决方案。
Since I don't yet have enough rep to comment, I'm forced to add this as a "question":
由于我还没有足够的代表发表评论,我不得不将其添加为“问题”:
public static IPAddress GetDefaultGateway()
{
IPAddress result = null;
var cards = NetworkInterface.GetAllNetworkInterfaces().ToList();
if (cards.Any())
{
foreach (var card in cards)
{
var props = card.GetIPProperties();
if (props == null)
continue;
var gateways = props.GatewayAddresses;
if (!gateways.Any())
continue;
var gateway =
gateways.FirstOrDefault(g => g.Address.AddressFamily.ToString() == "InterNetwork");
if (gateway == null)
continue;
result = gateway.Address;
break;
};
}
return result;
}
回答by harsini
The first IP address returned by traceroutecommand will be the gateway .You can use this fact for getting gateway.A nice implementation of traceroutcan be found here:
TraceRoute and Ping in C#
traceroute命令返回的第一个 IP 地址将是网关。你可以使用这个事实来获取网关。可以tracerout在这里找到一个很好的实现:
TraceRoute and Ping in C#
回答by Wayne
NetworkInterface[] allNICs = NetworkInterface.GetAllNetworkInterfaces();
foreach (var nic in allNICs)
{
var ipProp = nic.GetIPProperties();
var gwAddresses = ipProp.GatewayAddresses;
if (gwAddresses.Count > 0 &&
gwAddresses.FirstOrDefault(g => g.Address.AddressFamily == AddressFamily.InterNetwork) != null)
{
localIP = ipProp.UnicastAddresses.First(d => d.Address.AddressFamily == AddressFamily.InterNetwork).Address;
}
}
Debug.Print(localIP.ToString());
回答by zero.zero.seven
according to @midspace's comment on @caesay's answer this is a better answer:
根据@midspace 对@caesay 回答的评论,这是一个更好的答案:
public static IPAddress GetDefaultGateway()
{
var gateway_address = NetworkInterface.GetAllNetworkInterfaces()
.Where(e => e.OperationalStatus == OperationalStatus.Up)
.SelectMany(e => e.GetIPProperties().GatewayAddresses)
.FirstOrDefault();
if (gateway_address == null) return null;
return gateway_address.Address;
}
I'm warning that it's not a complete solution, if your'e looking for the main interface responsible for the internet access, you should combine other approaches like using win32 API GetBestInterfaceto find the best interface to connect to a destination address.
我警告说这不是一个完整的解决方案,如果您正在寻找负责互联网访问的主接口,您应该结合其他方法,例如使用 win32 API GetBestInterface来找到连接到目标地址的最佳接口。
you can find example usage here: http://www.pinvoke.net/default.aspx/iphlpapi.getbestinterface
你可以在这里找到示例用法:http: //www.pinvoke.net/default.aspx/iphlpapi.getbestinterface
回答by Nick Randell
I've just come across this and will be using the following code - basically it looks for interfaces that aren't loopback and are up and have gateways and unicast addresses. From the interface I then get a non transient IPV4 address.
我刚刚遇到了这个并将使用以下代码 - 基本上它会查找不是环回且已启动并具有网关和单播地址的接口。然后,我从界面中获得了一个非瞬态 IPV4 地址。
public static class NetworkInterfaces
{
public static NetworkInterface GetDefaultInterface()
{
var interfaces = System.Net.NetworkInformation.NetworkInterface.GetAllNetworkInterfaces();
foreach (var intf in interfaces)
{
if (intf.OperationalStatus != OperationalStatus.Up)
{
continue;
}
if (intf.NetworkInterfaceType == NetworkInterfaceType.Loopback)
{
continue;
}
var properties = intf.GetIPProperties();
if (properties == null)
{
continue;
}
var gateways = properties.GatewayAddresses;
if ((gateways == null) || (gateways.Count == 0))
{
continue;
}
var addresses = properties.UnicastAddresses;
if ((addresses == null) || (addresses.Count == 0))
{
continue;
}
return intf;
}
return null;
}
public static IPAddress GetDefaultIPV4Address(NetworkInterface intf)
{
if (intf == null)
{
return null;
}
foreach (var address in intf.GetIPProperties().UnicastAddresses)
{
if (address.Address.AddressFamily != AddressFamily.InterNetwork)
{
continue;
}
if (address.IsTransient)
{
continue;
}
return address.Address;
}
return null;
}
}
回答by Cameron
Been looking for one weird trick to determine the local IP address? Yet do it very robustly vs. the earlier methods?
一直在寻找一种奇怪的技巧来确定本地 IP 地址?然而,与早期的方法相比,它是否非常稳健?
[See end for response to @caesay]
[对@caesay 的回复见结尾]
This may be what you are looking for.
这可能就是您正在寻找的。
using (var s = new System.Net.Sockets.Socket(AddressFamily.InterNetwork, SocketType.Dgram,ProtocolType.Udp))
{
s.Bind( new System.Net.IPEndPoint(System.Net.IPAddress.Any,0));
s.Connect("google.com",0);
var ipaddr = s.LocalEndPoint as System.Net.IPEndPoint;
var addr = ipaddr.Address.ToString();
Console.WriteLine(addr);
}
That will create a UDP socket, but will not send data on it. You can then see what local interface and address the socket was bound to. You must supply an IP address or hostname where I used google.com, that will be used by the OS to determine which interface the socket will be bound to, and what IP address you will find using this method. For 99%+ of IP addresses or hostnames you use, you will get the interface+address to be used for traffic over the default route.
这将创建一个 UDP 套接字,但不会在其上发送数据。然后,您可以查看套接字绑定到的本地接口和地址。您必须提供我使用 google.com 的 IP 地址或主机名,操作系统将使用它来确定套接字将绑定到哪个接口,以及您将使用此方法找到的 IP 地址。对于您使用的 99% 以上的 IP 地址或主机名,您将获得用于通过默认路由进行流量的接口+地址。
While this is a little obtuse, I suspect it is more reliable than the methods above where people use the PInvoke call and scan through the structures to see if they can find the interface.
虽然这有点笨拙,但我怀疑它比上面的方法更可靠,人们使用 PInvoke 调用并扫描结构以查看他们是否可以找到接口。
I certainly found it more robust on my 3x double interface systems than scanning through the results of NetworkInterface.GetAllNetworkInterfaces() using heuristics to try to figure out the default interface address.
我当然发现它在我的 3x 双接口系统上比使用试探法扫描 NetworkInterface.GetAllNetworkInterfaces() 的结果来尝试找出默认接口地址更强大。
[Update/response to @caesay 2/6/2019] @caesay Has made an excellent point here, so I have switched the sample from using UdpClient to Socket, and explicitly called Socket.Connect() after Bind(). I have also reviewed the Framework source for Connect() and LocalEndPoint, and both call their corresponding Win32 OS system call immediately without deferring or being lazy about calling into the OS. The Win32 bind page says "The application can use getsockname after calling bind to learn the address and the port that has been assigned to the socket. If the Internet address is equal to INADDR_ANY or in6addr_any, getsockname cannot necessarily supply the address until the socket is connected". This condition is now explicitly addressed, and having reviewed the Framework source, the IP address should always be available after the Connect() call.
[更新/回复@caesay 2/6/2019] @caesay 在这里提出了一个很好的观点,所以我将示例从使用 UdpClient 切换到 Socket,并在 Bind() 之后显式调用 Socket.Connect()。我还查看了 Connect() 和 LocalEndPoint 的框架源代码,它们都立即调用了它们对应的 Win32 操作系统系统调用,而不会延迟或懒惰地调用操作系统。Win32绑定页面说“应用程序可以在调用bind后使用getsockname来了解已分配给套接字的地址和端口。如果Internet地址等于INADDR_ANY或in6addr_any,则getsockname不一定提供地址,直到套接字被连接的”。现在明确解决了这种情况,并且在查看了框架源之后,在 Connect() 调用之后 IP 地址应该始终可用。

