我对提出的解决方案有疑问,使用lookup
并不总是返回期望值。
这是由于DNS缓存所致,该调用的值被缓存,并且在下次尝试返回该缓存的值时尝试进行适当的调用。当然,这是一个问题,因为这意味着如果您失去连接并调用lookup
它仍可以像使用互联网一样返回缓存的值,反之,如果您在lookup
返回null后重新连接互联网,则在访问期间仍将返回null。缓存,即使您现在已经连接互联网,也可能需要几分钟。
TL; DR:lookup
返回某些内容并不一定意味着您具有互联网,并且不返回任何内容并不一定意味着您没有互联网。这是不可靠的。
我从data_connection_checker
插件中汲取了灵感,实现了以下解决方案:
Future<bool> _checkInternetAccess() {
final List<InternetAddress> dnss = [
InternetAddress('8.8.8.8', type: InternetAddressType.IPv4),
InternetAddress('2001:4860:4860::8888', type: InternetAddressType.IPv6),
InternetAddress('1.1.1.1', type: InternetAddressType.IPv4),
InternetAddress('2606:4700:4700::1111', type: InternetAddressType.IPv6),
InternetAddress('208.67.222.222', type: InternetAddressType.IPv4),
InternetAddress('2620:0:ccc::2', type: InternetAddressType.IPv6),
InternetAddress('180.76.76.76', type: InternetAddressType.IPv4),
InternetAddress('2400:da00::6666', type: InternetAddressType.IPv6),
];
final Completer<bool> completer = Completer<bool>();
int callsReturned = 0;
void onCallReturned(bool isAlive) {
if (completer.isCompleted) return;
if (isAlive) {
completer.complete(true);
} else {
callsReturned++;
if (callsReturned >= dnss.length) {
completer.complete(false);
}
}
}
dnss.forEach((dns) => _pingDns(dns).then(onCallReturned));
return completer.future;
}
Future<bool> _pingDns(InternetAddress dnsAddress) async {
const int dnsPort = 53;
const Duration timeout = Duration(seconds: 3);
Socket socket;
try {
socket = await Socket.connect(dnsAddress, dnsPort, timeout: timeout);
socket?.destroy();
return true;
} on SocketException {
socket?.destroy();
}
return false;
}
呼叫_checkInternetAccess
最多需要一个持续时间timeout
(此处为3秒),如果我们可以访问任何一个DNS,则它将在到达第一个DNS时立即完成,而无需等待其他DNS(到达一个就足以知道你有互联网)。所有的呼叫_pingDns
都是并行进行的。
它似乎可以在IPV4网络上很好地工作,当我不能在IPV6网络上对其进行测试(我无法访问它)时,我认为它仍然可以工作。它也适用于发布模式版本,但是我还必须将我的应用程序提交给Apple,以查看他们是否发现此解决方案有任何问题。
它也应在大多数国家(包括中国)中工作,如果在一个国家中不起作用,则可以将DNS添加到目标国家/地区可以访问的列表中。