Παρατηρητής κατάστασης OpenVPN σε C#: παρακολουθήστε τη συνεδρία, όχι την κάρτα δικτύου
Το NetworkAvailabilityChanged δεν είναι συμβάν VPN. Διαβάστε τη ροή κατάστασης του πελάτη που κατέχει τη σήραγγα, προφυλαχθείτε από παρωχημένους ελέγχους και δημοσιεύστε ετοιμότητα ανά σύνδεση.
Η εφαρμογή σας συνεχίζει να λειτουργεί ενώ η σήραγγα πεθαίνει. Το Wi-Fi είναι ακόμη ενεργό, το διαδίκτυο ακόμη απαντά, και το ιδιωτικό API από το οποίο εξαρτάται η εφαρμογή έχει γίνει μη προσπελάσιμο. Το συμβάν .NET στο οποίο καταφεύγουν συνήθως εδώ, NetworkAvailabilityChanged, δεν περιγράφει καθόλου αυτή την κατάσταση. Αναφέρει αλλαγή στη συνολική κατάσταση του μηχανήματος, και αυτή η κατάσταση μπορεί να παραμείνει αληθής κατά την αποσύνδεση και επανασύνδεση VPN. Ένας παρατηρητής πρέπει να παρακολουθεί τον πελάτη που κατέχει τη σήραγγα, όχι τη σύνοψη της στοίβας δικτύου.
Η διαθεσιμότητα είναι συνολικό μέγεθος, όχι η σήραγγά σας
NetworkAvailabilityChanged ενεργοποιείται όταν αλλάζει η συνολική απάντηση διαθεσιμότητας του μηχανήματος, και αυτή η απάντηση μετρά κάθε ενεργή διεπαφή εκτός από loopback ή σήραγγα.
Μια πτώση VPN με ενεργό Wi-Fi δεν αλλάζει τίποτα από όσα μετρά, γι' αυτό το συμβάν μπορεί να μείνει σιωπηλό ακριβώς κατά την αστοχία που σας απασχολεί.
Η ροή κατάστασης ανήκει στον πελάτη που κατέχει τη σήραγγα
Προσδιορίστε ποιο στοιχείο κατέχει τη σύνδεση: το GUI ή την υπηρεσία OpenVPN, το OpenVPN Connect, ή μια διεργασία που ξεκίνησε και ελέγχει η εφαρμογή σας. Είναι διαφορετικοί ιδιοκτήτες με διαφορετικές υποστηριζόμενες διεπαφές, και ο παρατηρητής πρέπει να χρησιμοποιεί αυτή που ταιριάζει στην ανάπτυξη. Για διεργασία OpenVPN με την οποία έχετε εξουσιοδότηση ενσωμάτωσης, η διεπαφή διαχείρισης αναφέρει την τρέχουσα κατάσταση, ιστορικό και ειδοποιήσεις σε πραγματικό χρόνο. Αναλύστε τα τεκμηριωμένα δομημένα μηνύματα αντί να αναζητάτε τη λέξη connected σε μεταφρασμένη λεζάντα GUI.
Το κανάλι διαχείρισης είναι προνομιακή επιφάνεια ελέγχου, οπότε μην ανοίγετε νέο ακροατή και μην διαπληκτίζεστε με το GUI για κανάλι που ήδη κρατά.
Οι φρουροί γενιάς σταματούν τα παρωχημένα αποτελέσματα
Κάθε παρατήρηση ανήκει σε συγκεκριμένη απόπειρα σύνδεσης. Αυξήστε έναν μετρητή γενιάς όταν ξεκινά νέα απόπειρα, όταν χάνεται το κανάλι και όταν ο πελάτης αναφέρει έξοδο.
Σκεφτείτε έναν έλεγχο που ξεκίνησε κατά τη σύνδεση A. Η σήραγγα πέφτει, ξεκινά η σύνδεση B, και μετά φτάνει η καθυστερημένη επιτυχία HTTP της A. Χωρίς φρουρό, εκείνο το παλιό αποτέλεσμα κάνει την οθόνη πράσινη ενώ η B ακόμη πιστοποιείται. Η ακύρωση μειώνει τη χαμένη εργασία, και ο έλεγχος γενιάς είναι αυτό που εμποδίζει μια παρωχημένη ολοκλήρωση να γίνει τρέχουσα κατάσταση:
var generation = _generation;
var reachable = await ProbeAsync(token);
if (generation != _generation) return;
Publish(reachable);
Εφαρμόστε τον ίδιο κανόνα γύρω από την αποστολή στο UI, γιατί η συσκευασμένη ενημέρωση μπορεί να φτάσει αφού η γενιά έχει προχωρήσει.
Η αρχικοποίηση και η επανασύνδεση είναι ένας κύκλος ζωής
Αντιμετωπίστε την πρώτη σύνδεση, την επανασύνδεση και την απώλεια καναλιού ως έναν κύκλο ζωής με ένα σύνολο κανόνων:
- Διαβάστε την τρέχουσα κατάσταση και εγγραφείτε σε ειδοποιήσεις σε ένα βήμα όπου η διεπαφή το επιτρέπει.
- Σημάνετε κάθε παρατήρηση με την ταυτότητα της σύνδεσης και τη γενιά.
- Ακυρώστε την ετοιμότητα στην επανασύνδεση, την έξοδο ή ένα χαμένο κανάλι παρατήρησης.
- Ελέγξτε τον ιδιωτικό πόρο μόνο αφού ο ιδιοκτήτης αναφέρει ολοκλήρωση της αρχικοποίησης.
- Δημοσιεύστε μόνο αποτελέσματα που ανήκουν ακόμη στην τρέχουσα γενιά.
Ένα χαμένο κανάλι σημαίνει άγνωστο, όχι αποσυνδεδεμένο. Το να αναφέρετε άγνωστο είναι πιο έντιμο από το να αναφέρετε αποσύνδεση που δεν μπορείτε να αποδείξετε, και εμποδίζει τη λογική επανάληψης να ενεργεί βάσει εικασίας.
Αναφέρετε στοιχεία, όχι μια λογική τιμή
Επιστρέψτε την ονομασμένη κατάσταση συνεδρίας και την ετοιμότητα πόρου ως ξεχωριστές τιμές, καθεμία με ηλικία. Ένας καταναλωτής που πρέπει να αποφασίσει κάτι μπορεί τότε να δει ότι ο τελευταίος επιτυχής έλεγχος είναι σαράντα δευτερολέπτων, που είναι διαφορετική πληροφορία από μια φρέσκια.
Η αναζήτηση δημόσιας IP δεν είναι απόδειξη ότι ένα ιδιωτικό API χρησιμοποίησε την απαιτούμενη διαδρομή, οπότε μην την παρουσιάζετε σαν να ήταν.
Κρατήστε την επιβολή έξω από τον παρατηρητή
Ένα callback εκτελείται εκ των υστέρων. Δεν μπορεί να εγγυηθεί ότι κανένα πακέτο δεν έφυγε από το μηχάνημα μεταξύ συμβάντος και χειριστή. Αν ο σχεδιασμός απαιτεί αποκλεισμό, η πολιτική δικτύου πρέπει να τον παρέχει, και το έργο του παρατηρητή είναι να εξηγήσει τα στοιχεία στον καλούντα. Η ανάμειξη των δύο παράγει κώδικα που πιστεύει ότι είναι τείχος προστασίας επειδή κρατά μια λογική τιμή. Κρατήστε το επίπεδο επιβολής βαρετό και δοκιμάσιμο, και αφήστε τον παρατηρητή να παραμείνει αναγνώστης.
Τότε το ερώτημα του UI γίνεται απλό: δείξτε τι είναι γνωστό, με την ηλικία του, και πείτε άγνωστο όταν είναι.