Управляемая альтернатива для 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"));
Другие вопросы по тегам