Управляемая альтернатива для GetBestInterface?
У меня нет абсолютно никакого опыта программирования на C (или любых других неуправляемых языках в этом отношении), но я хотел бы использовать функцию GetBestInterface из API IP Helper в моем приложении.NET. Я попытался понять, как можно использовать вызовы P/invoke для выполнения вызовов нативных методов, но есть много вещей, которые для меня просто не имеют смысла (например, как типы в управляемом коде сопоставляются с неуправляемыми типами).
Есть ли где-нибудь скрытая альтернативная функция в пространстве имен System.Net, которая делает примерно то же самое? Или я мог бы написать свою собственную альтернативу, используя существующие базовые классы в сочетании с некоторой магией? Потому что это в основном то, что мне кажется: магия. Насколько я могу судить, нет реального объяснения того, как метод выполняет то, что он делает.
РЕДАКТИРОВАТЬ
Я только что обнаружил свойство LocalEndPoint на System.Net.Sockets.Socket
класс, который я думаю, может быть весьма полезным в этом. Насколько я понимаю, он сделает лучший выбор интерфейса от моего имени, и мне просто нужно получить сетевой адаптер, соответствующий локальной конечной точке.
1 ответ
Хорошо, я сам собрал что-то, что работает за счет возможности фреймворка самостоятельно выбирать интерфейс. По сути, он просто подключает сокет, а затем использует свойство LocalEndPoint для сокета, чтобы получить NIC, который он использует. Вероятно, не самый лучший способ сделать это, но это работает для меня.
Используя следующие операторы импорта:
Imports System.Net
Imports System.Net.NetworkInformation
Imports System.Net.Sockets
И мой супер удивительный метод:
Private Function GetBestInterfaceManaged(ByVal address As IPAddress, ByVal port As Integer) As NetworkInterface
Dim socket As Socket = New Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.IP)
Dim outgoingInterface As NetworkInterface = Nothing
Try
socket.Connect(New IPEndPoint(address, port))
If socket.Connected Then ' find the outgoing NIC
Dim interfaces As List(Of NetworkInterface) = NetworkInterface.GetAllNetworkInterfaces.ToList()
For Each nic As NetworkInterface In interfaces
Dim properties As IPInterfaceProperties = nic.GetIPProperties
For Each unicastAddress In properties.UnicastAddresses
If unicastAddress.Address.Equals(DirectCast(socket.LocalEndPoint, IPEndPoint).Address) Then
outgoingInterface = nic
End If
Next
Next
If outgoingInterface Is Nothing Then
Console.WriteLine("Darn... it didn't work!")
Else
Console.WriteLine("Outgoing interface: {0}", outgoingInterface.Name)
End If
Return outgoingInterface
End If
Catch ex As SocketException
Console.WriteLine(ex.Message)
End Try
Return Nothing
End Function
Это сделает свое дело:
Sub Main()
Dim hostEntry As IPHostEntry = Dns.GetHostEntry("www.stackru.com")
Dim NIC As NetworkInterface = GetBestInterfaceManaged(hostEntry.AddressList.First, 80)
' Other code goes down here
End Sub
Я также требуется GetBestInterface
так как мне нужно решение, которое работает, если удаленный адрес для проверки недоступен (что-то, с чем у Стивена может возникнуть проблема), и чтобы он был на 100% совместим с нативным приложением, которое я переносил на C#.
К счастью, вам не нужно переносить GetAdaptersInfo
и все соответствующие IP_ADAPTER_INFO
и подструктура беспорядка, чтобы найти, какой сетевой интерфейс имеет индекс, возвращаемый GetBestInterface
, поскольку .NET уже может извлечь этот индекс из интерфейсов.
Итак, первый порт GetBestInterface
метод следующим образом:
[DllImport("iphlpapi")]
private static extern int GetBestInterface(uint dwDestAddr, ref uint pdwBestIfIndex);
Затем напишите функцию-обертку следующим образом:
private static NetworkInterface GetBestNetworkInterface(IPAddress remoteAddress)
{
// Get the index of the interface with the best route to the remote address.
uint dwDestAddr = BitConverter.ToUInt32(remoteAddress.GetAddressBytes());
uint dwBestIfIndex = 0;
uint result = GetBestInterface(dwDestAddr, ref dwBestIfIndex);
if (result != 0)
throw new NetworkInformationException((int)result);
// Find a matching .NET interface object with the given index.
foreach (NetworkInterface networkInterface in NetworkInterface.GetAllNetworkInterfaces())
if (networkInterface.GetIPProperties().GetIPv4Properties().Index == dwBestIfIndex)
return networkInterface;
throw new InvalidOperationException($"Could not find best interface for {remoteAddress}.");
}
Затем вы можете просто вызвать метод следующим образом - и не забудьте, что недоступные хосты теперь также работают:
NetworkInterface bestNetworkInterface = GetBestNetworkInterface(IPAddress.Parse("8.8.8.8"));