我们的 Delphi /Indy应用程序使用IPv4上的mDNS发现设备,但发现的一些地址是链路本地IPv6地址(在AAAA
记录中与其他A
记录沿着指定)。我们希望提供使用IPv4或IPv6地址连接到设备的选项,因为有些人坚持设置静态IPv4地址,而这些地址会由于位置或配置的更改而变为与它们所在的子网不兼容。
但是,当应用程序尝试建立到这些链路本地IPv6地址之一的TCP连接时,第一次尝试通常会失败,因为Windows不知道使用哪个接口。(仅从命令行ping地址时也会观察到相同的行为。通过在链路本地地址的末尾写入%并在后面加上相应的区域ID,可以解决此问题。)
因此,用于连接到设备的TIdTCPClient
对象需要与正确的网络接口关联。我知道这可以通过设置BoundIP
属性来完成,但我没有发现设备的接口的IPv6地址,因为这是使用IPv4完成的。是否有一种方法可以在发现设备时使用OnUDPRead
事件中提供的TIdSocketHandle
对象,并使用该对象在TIdTCPClient
对象中设置适当的内容?
2条答案
按热度按时间7eumitmz1#
但是,当应用程序尝试建立到这些链路本地IPv6地址之一的TCP连接时,第一次尝试通常会失败,因为Windows不知道要使用哪个接口。
您是否将
TIdTCPClient.IPVersion
属性设置为Id_IPv6
?Indy当前无法根据指定的IP地址(ticket)确定要连接的IP版本,您必须事先明确指定IP版本。大多数情况下,让Windows决定连接到IP地址时使用哪个接口就足够了,这就是它的路由表的作用。
如果只从命令行ping地址,也会出现同样的情况。通过在链路本地地址的末尾写入%,然后加上相应的区域ID,可以解决此问题。
Indy目前不支持IPv6地址的区域/范围ID(ticket)。
是否有一种方法可以在发现设备时使用
OnUDPRead
事件中提供的TIdSocketHandle
对象不太可能,因为您说发现是通过IPv4进行的,这意味着
TIdSocketHandle
的UDP套接字绑定到了IPv4接口,而不是IPv6接口。唯一的可能性是,如果有问题的接口同时分配了IPv4和IPv6地址,在这种情况下,您可以使用Win32 API将TIdSocketHandle.IP
匹配到特定的接口,然后枚举同一接口上的IPv6地址。否则,您可以使用Indy的
TIdStack.GetLocalAddressList()
方法获取所有本地IPv6接口IP,然后将TIdTCPClient
绑定到循环中的每个接口,直到成功连接到目标设备。kyks70gy2#
我采纳了雷米的建议,实施了以下措施:
由于设备发现是通过IPv4完成的,因此网络接口的IPv4地址是已知的(
TIdSocketHandle
的IP
属性),因此通过使用上述函数,可以设置TIdTCPClient.BoundIP
,以便网络接口对于在发现过程中找到的任何链路本地IPv6地址都是明确的。