c#知道我们使用哪个IP与另一个IP通信吗
本文关键字:IP 另一个 通信 我们 | 更新日期: 2023-09-27 18:01:15
使用自制的发现工具,我发现了我感兴趣的服务列表。
我有他们的IP,服务名称,端口,主机。。。但要使用它们,我必须向客户端库指定我们将要使用的IP。
由于我有几个网卡,我需要检测哪个接口用于与我知道的目标IP通信,然后将这个IPAddress
提供给我的库。
但是我怎么能检测到我应该使用哪个接口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;
}