c#知道我们使用哪个IP与另一个IP通信吗

本文关键字:IP 另一个 通信 我们 | 更新日期: 2023-09-27 18:01:15

使用自制的发现工具,我发现了我感兴趣的服务列表。

我有他们的IP,服务名称,端口,主机。。。但要使用它们,我必须向客户端库指定我们将要使用的IP。

由于我有几个网卡,我需要检测哪个接口用于与我知道的目标IP通信,然后将这个IPAddress提供给我的库。

但是我怎么能检测到我应该使用哪个接口IP呢?

我试着在互联网上搜索,但我觉得我没有找到合适的关键词,因为我找不到任何相关的东西。

c#知道我们使用哪个IP与另一个IP通信吗

我已经从我为之开发的网络库networkComms.net:中为您提取了相关方法

/// <summary>
/// Determines the most appropriate local end point to contact the provided remote end point. 
/// Testing shows this method takes on average 1.6ms to return.
/// </summary>
/// <param name="remoteIPEndPoint">The remote end point</param>
/// <returns>The selected local end point</returns>
public static IPEndPoint BestLocalEndPoint(IPEndPoint remoteIPEndPoint)
{    
    Socket testSocket = new Socket(remoteIPEndPoint.AddressFamily, SocketType.Dgram, ProtocolType.Udp);
    testSocket.Connect(remoteIPEndPoint);
    return (IPEndPoint)testSocket.LocalEndPoint;
}

一旦您有了正确的IP,就可以在NetworkInterface.GetAllNetworkInterfaces()上进行迭代以定位匹配的适配器。

以下是通过查询路由表实现的。这与Socket.Connect确定要使用的本地端点的方式相同。差异:

  • 不能由于防火墙而失败
  • 不能由于不存在远程终结点而失败
  • 没有预订本地端口
  • 更快

private static IPEndPoint QueryRoutingInterface(
          Socket socket,
          IPEndPoint remoteEndPoint)
{
    SocketAddress address = remoteEndPoint.Serialize();
    byte[] remoteAddrBytes = new byte[address.Size];
    for (int i = 0; i < address.Size; i++) {
        remoteAddrBytes[i] = address[i];
    }
    byte[] outBytes = new byte[remoteAddrBytes.Length];
    socket.IOControl(
                IOControlCode.RoutingInterfaceQuery, 
                remoteAddrBytes, 
                outBytes);
    for (int i = 0; i < address.Size; i++) {
        address[i] = outBytes[i];
    }
    EndPoint ep = remoteEndPoint.Create(address);
    return (IPEndPoint)ep;
}

其用途类似于:

IPAddress remoteIp = IPAddress.Parse("192.168.1.55");
IpEndPoint remoteEndPoint = new IPEndPoint(remoteIp, 0);
Socket socket = new Socket(
                      AddressFamily.InterNetwork, 
                      SocketType.Dgram, 
                      ProtocolType.Udp);
IPEndPoint localEndPoint = QueryRoutingInterface(socket, remoteEndPoint );
Console.WriteLine("Local EndPoint is: {0}", localEndPoint);

(源代码从这里复制(

请注意,尽管指定了带有端口的IpEndPoint,但该端口是不相关的。此外,返回的IpEndPoint.Port总是0

我花了几个小时来寻找这个问题的简短答案,多亏了BatteryBackupUnit,我制定了这个解决方案,并希望它能帮助其他程序员:

    [DllImport("ws2_32.dll", SetLastError = true)]
    private static extern SocketError WSAIoctl([In] IntPtr socketHandle, uint ioControlCode, [In] byte[] inBuffer, int inBufferSize, [Out] byte[] outBuffer, int outBufferSize, out int bytesTransferred, IntPtr overlapped, IntPtr completionRoutine);
    /// <summary>Get local IP-address for remote address</summary>
    /// <param name="remoteAddress">Remote Address</param>
    /// <returns></returns>
    public static IPAddress GetLocalAddressForRemote(IPAddress remoteAddress)
    {
        if (remoteAddress == null) return null;
        long rm = remoteAddress.Address;
        //Temporary socket only for handle of it
        Socket s = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
        byte[] src = new byte[16];
        src[0] = 2;
        src[4] = (byte)rm;
        src[5] = (byte)(rm >> 8);
        src[6] = (byte)(rm >> 16);
        src[7] = (byte)(rm >> 24);
        int transeferred = 0;
        if (WSAIoctl(s.Handle, 3355443220, src, 16, src, 16, out transeferred, IntPtr.Zero, IntPtr.Zero) == SocketError.Success)
        {
            s.Dispose();
            rm = src[4];
            rm |= ((long)src[5]) << 8;
            rm |= ((long)src[6]) << 16;
            rm |= ((long)src[7]) << 24;
            return new IPAddress(rm);
        }
        s.Dispose();
        return null;
    }