ฉันมีปัญหากับแนวทางแก้ไขที่เสนอโดยการใช้lookup
ไม่ได้ส่งคืนค่าที่คาดหวังเสมอไป
เนื่องจากการแคช DNS ค่าของการโทรจะถูกแคชและตั้งใจที่จะทำการโทรที่เหมาะสมในการลองครั้งถัดไปจะให้ค่าแคชกลับมา แน่นอนว่านี่เป็นปัญหาที่นี่เนื่องจากหมายความว่าหากคุณสูญเสียการเชื่อมต่อและเรียกlookup
ได้ว่ายังสามารถคืนค่าแคชได้ราวกับว่าคุณมีอินเทอร์เน็ตและในทางกลับกันหากคุณเชื่อมต่ออินเทอร์เน็ตอีกครั้งหลังจากlookup
ส่งคืนค่าว่างมันจะยังคงคืนค่าว่างตลอดระยะเวลาของ แคชซึ่งอาจใช้เวลาไม่กี่นาทีแม้ว่าคุณจะมีอินเทอร์เน็ตแล้วก็ตาม
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 แรกโดยไม่ต้องรอผู้อื่น (เนื่องจากการเข้าถึงหนึ่งเพียงพอที่จะ รู้ว่าคุณมีอินเทอร์เน็ต) การโทรทั้งหมด_pingDns
จะทำแบบขนาน
ดูเหมือนว่าจะทำงานได้ดีบนเครือข่าย IPV4 และเมื่อฉันไม่สามารถทดสอบบนเครือข่าย IPV6 ได้ (ฉันไม่สามารถเข้าถึงได้) ฉันคิดว่ามันน่าจะยังใช้งานได้ นอกจากนี้ยังใช้งานได้กับการสร้างโหมดเผยแพร่ แต่ฉันยังต้องส่งแอพของฉันไปยัง Apple เพื่อดูว่าพวกเขาพบปัญหาใด ๆ กับโซลูชันนี้หรือไม่
นอกจากนี้ควรใช้งานได้ในประเทศส่วนใหญ่ (รวมถึงจีน) หากใช้ไม่ได้ในประเทศเดียวคุณสามารถเพิ่ม DNS ลงในรายการที่สามารถเข้าถึงได้จากประเทศเป้าหมายของคุณ