我之前在 Stack Overflow 上问过这个问题,有人建议我将这个问题转到 Server Fault。所以我就在这里 :)
我正在使用的应用程序连接到在不同计算机上运行的几个 TCP 服务器。
有一次,我们将全新的 Windows 安装带到现场,安装了我们的应用程序,将 2 个相关网络插入客户端计算机,最终应用程序无法连接到其中一个服务器,而另一个服务器可以正常连接。这是 ipconfig 输出的屏幕截图:
我们无法连接的服务器有 IP 地址192.168.3.2
。运行应用程序的客户端有 IP 地址192.168.3.1
。
最后,这是路线打印的输出:
IPv4 Route Table
===========================================================================
Active Routes:
Network Destination Netmask Gateway Interface Metric
0.0.0.0 0.0.0.0 192.168.42.1 192.168.42.136 291
127.0.0.0 255.0.0.0 On-link 127.0.0.1 331
127.0.0.1 255.255.255.255 On-link 127.0.0.1 331
127.255.255.255 255.255.255.255 On-link 127.0.0.1 331
192.168.42.0 255.255.255.0 On-link 192.168.42.136 291
192.168.42.136 255.255.255.255 On-link 192.168.42.136 291
192.168.42.255 255.255.255.255 On-link 192.168.42.136 291
224.0.0.0 240.0.0.0 On-link 127.0.0.1 331
224.0.0.0 240.0.0.0 On-link 192.168.42.136 291
255.255.255.255 255.255.255.255 On-link 127.0.0.1 331
255.255.255.255 255.255.255.255 On-link 192.168.42.136 291
===========================================================================
Persistent Routes:
Network Address Netmask Gateway Address Metric
192.168.3.0 255.255.255.0 192.168.3.1 1
0.0.0.0 0.0.0.0 192.168.42.1 Default
===========================================================================
我们观察到,在尝试连接时,客户端应用程序日志正在转储此内容:IpUtility.CheckIPRouting IP address 192.168.3.2 incorrectly routed through 192.168.42.136
。
我们打开了应用程序源代码,发现它所做的就是查询用于特定远程 IP 地址的接口(我不是特别明白):
以下是其中的片段CheckIPRouting
:
public static void CheckIPRouting(IPAddress iPAddressTarget, IPAddress ipAddressGateway)
{
IPEndPoint remoteEndPoint = new IPEndPoint(iPAddressTarget, 0);
Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
IPAddress localEndPoint = QueryRoutingInterface(socket, remoteEndPoint);
if (localEndPoint.Equals(ipAddressGateway))
{
log.Trace($"IP address {iPAddressTarget} correctly routed through {localEndPoint.MapToIPv4()}");
}
else
{
log.Debug($"IP address {iPAddressTarget} incorrectly routed through {localEndPoint.MapToIPv4()}");
}
}
这是QueryRoutingInterface
:
private static IPAddress 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).Address;
}
后来,我们注意到客户端应用程序代码也有一个设置,可以强制通过接口 IP 地址进行连接,代码如下:
logger.Info("Creating tcpClient for {0} using address {1}", connectionResourceName, adapterAddress);
IPEndPoint adapter = new IPEndPoint(adapterAddress, 0);
tcpClient = new TcpClient(adapter);
在应用程序日志中可以清楚地看到:
Creating tcpClient for RESOURCE using address 192.168.3.1
这时我感到很困惑。然后我决定更改应用程序的配置,不再使用192.168.3.1
接口来建立连接,而是将接口地址更改为0.0.0.0
。
然后连接就建立了!
此时的路线打印变为:
IPv4 Route Table
===========================================================================
Active Routes:
Network Destination Netmask Gateway Interface Metric
0.0.0.0 0.0.0.0 192.168.42.1 192.168.42.136 291
127.0.0.0 255.0.0.0 On-link 127.0.0.1 331
127.0.0.1 255.255.255.255 On-link 127.0.0.1 331
127.255.255.255 255.255.255.255 On-link 127.0.0.1 331
192.168.3.0 255.255.255.0 On-link 192.168.3.1 2
192.168.3.1 255.255.255.255 On-link 192.168.3.1 257
192.168.3.255 255.255.255.255 On-link 192.168.3.1 257
192.168.42.0 255.255.255.0 On-link 192.168.42.136 291
192.168.42.136 255.255.255.255 On-link 192.168.42.136 291
192.168.42.255 255.255.255.255 On-link 192.168.42.136 291
224.0.0.0 240.0.0.0 On-link 127.0.0.1 331
224.0.0.0 240.0.0.0 On-link 192.168.42.136 291
224.0.0.0 240.0.0.0 On-link 192.168.3.1 257
255.255.255.255 255.255.255.255 On-link 127.0.0.1 331
255.255.255.255 255.255.255.255 On-link 192.168.42.136 291
255.255.255.255 255.255.255.255 On-link 192.168.3.1 257
===========================================================================
Persistent Routes:
Network Address Netmask Gateway Address Metric
192.168.3.0 255.255.255.0 192.168.3.1 1
0.0.0.0 0.0.0.0 192.168.42.1 Default
===========================================================================
然后我决定恢复客户端应用程序的配置,以像以前一样强制通过 192.168.3.1 适配器进行连接,并且连接正常建立。
然后,我比较了 2 条路线图(前后)。我注意到第二条路线图上有以下新条目:
192.168.3.0 255.255.255.0 On-link 192.168.3.1 2
192.168.3.1 255.255.255.255 On-link 192.168.3.1 257
192.168.3.255 255.255.255.255 On-link 192.168.3.1 257
224.0.0.0 240.0.0.0 On-link 192.168.3.1 257
255.255.255.255 255.255.255.255 On-link 192.168.3.1 257
我猜这些会产生很大的不同。但我认为持久的路线就可以做到这一点。
最后,我来回答一下这个问题:
为什么 Windows 会忽略持久路由并决定通过错误的接口路由 TCP 数据包?我怎样才能确保万无一失,让 Windows 不会做出错误的决定?
作为参考,这是 Windows 10 IoT Enterprise。
答案1
您添加的持久路线是不必要的,可能是错误的。
持久路线: 网络地址 网络掩码 网关地址 度量 192.168.3.0 255.255.255.0 192.168.3.1 1
您对 Windows 说:“通过 192.168.3.1 网关发送所有发往 192.168.3.0/24 子网的通信。”
192.168.3.0/24 是直连网络。无需任何路由即可进行通信。
在第一个route print
输出中,没有关于如何与 192.168.3.0/24 网络通信的信息。这可能是由于接口关闭/电缆断开造成的。您可以在不同的机器上重现此问题吗?