shutdown#
Τερματίζει τη μία κατεύθυνση μιας σύνδεσης υποδοχής, ή και τις δύο.
Η shutdown λέει στον πυρήνα να σταματήσει μια υποδοχή να κάνει περαιτέρω αναγνώσεις, περαιτέρω εγγραφές, ή και τα δύο - χωρίς να κλείσει τον περιγραφέα αρχείου. Σε αντίθεση με την close, η επίδραση είναι άμεση και διαδίδεται σε κάθε forked αντίγραφο του περιγραφέα, όχι μόνο σε αυτό της τρέχουσας διεργασίας. Το HOW έχει την ίδια σημασία με το όρισμα της κλήσης συστήματος shutdown(2).
Σύνοψη#
shutdown SOCKET, HOW
Τι επιστρέφεται#
1 σε επιτυχία. Σε αποτυχία, undef αν το SOCKET δεν είναι έγκυρο filehandle, ή 0 με την $! ορισμένη για κάθε άλλο σφάλμα (η υποδοχή δεν είναι συνδεδεμένη, έχει ήδη τερματιστεί σε εκείνη την κατεύθυνση, κ.ο.κ.).
Δύο διακριτές επιστροφές αποτυχίας, οπότε μερικές φορές χρειάζεται τριμερής έλεγχος:
my $r = shutdown($sock, 1);
if (!defined $r) { die "bad filehandle" }
elsif (!$r) { die "shutdown failed: $!" }
Το όρισμα HOW#
Το HOW είναι μικρός ακέραιος που ταιριάζει με τις σταθερές POSIX SHUT_*:
0- σταματά την ανάγνωση. Ο ομότιμος μπορεί ακόμη να στέλνει, αλλά τα δεδομένα θα απορρίπτονται από τον πυρήνα και ηread/sysreadσε αυτό το άκρο θα επιστρέφει τέλος αρχείου.1- σταματά την εγγραφή. Η έξοδος που είναι σε ουρά εκκενώνεται, και κατόπιν ο ομότιμος βλέπει τέλος αρχείου στο άκρο ανάγνωσής του. Ηprint/syswriteσε αυτό το άκρο θα αποτύχει και θα εγείρειSIGPIPE.2- σταματά και τις δύο κατευθύνσεις. Ισοδύναμο με κλήση τηςshutdownμε0και κατόπιν με1.
Τα συμβολικά ονόματα SHUT_RD, SHUT_WR, SHUT_RDWR βρίσκονται στο Socket αν προτιμάτε ευανάγνωστο κώδικα:
use Socket qw(SHUT_WR);
shutdown $sock, SHUT_WR;
shutdown έναντι close#
Η close απορρίπτει τον περιγραφέα αρχείου μόνο στην τρέχουσα διεργασία. Άλλες διεργασίες που κληρονόμησαν τον περιγραφέα μέσω fork κρατούν τα αντίγραφά τους ανοιχτά, και ο ομότιμος δεν βλέπει τέλος αρχείου μέχρι να κλείσει το τελευταίο αντίγραφο.
Η shutdown ενεργεί στην υποκείμενη υποδοχή, όχι στον περιγραφέα. Μετά από shutdown($sock, 1), κάθε forked αντίγραφο βλέπει το μισό εγγραφής κλειστό και ο ομότιμος διαβάζει τέλος αρχείου αμέσως - αν και ο ίδιος ο περιγραφέας παραμένει ανοιχτός και μπορεί ακόμη να διαβαστεί.
Αυτός είναι ο συνήθης λόγος να καταφύγει κανείς στη shutdown: γονέας και παιδί μοιράζονται μια υποδοχή, το παιδί τελείωσε την αποστολή και ο γονέας πρέπει να συνεχίσει να διαβάζει απαντήσεις. Η close στο παιδί θα ήταν αόρατη για τον ομότιμο· η shutdown($sock, 1) όχι.
Μισό κλείσιμο για πρωτόκολλα αίτησης/απάντησης#
Ένας πελάτης που στέλνει πλήρη αίτηση και κατόπιν χρειάζεται ο διακομιστής να γνωρίζει ότι δεν υπάρχει άλλη είσοδος χρησιμοποιεί shutdown με HOW = 1:
use IO::Socket::INET;
my $sock = IO::Socket::INET->new(PeerAddr => "example.com:80")
or die "connect: $!";
print $sock "GET / HTTP/1.0\r\nHost: example.com\r\n\r\n";
shutdown $sock, 1; # signal end-of-request to the server
while (my $line = <$sock>) {
print $line;
}
close $sock;
Χωρίς τη shutdown, οι διακομιστές που διαβάζουν μέχρι το τέλος εισόδου θα μπλόκαραν περιμένοντας περισσότερα δεδομένα αίτησης.
Παραδείγματα#
Διακοπή ανάγνωσης αλλά συνέχιση εγγραφής - ο ομότιμος μπορεί να συνεχίζει να στέλνει, απλώς δεν θα τα κοιτάμε:
shutdown $sock, 0;
Διακοπή εγγραφής, συνέχιση ανάγνωσης - τυπικό μισό κλείσιμο μετά την ολοκλήρωση αίτησης:
shutdown $sock, 1;
Πλήρης τερματισμός, και κατόπιν κλείσιμο του περιγραφέα:
shutdown $sock, 2;
close $sock;
Χρήση των σταθερών Socket για ευαναγνωσιμότητα:
use Socket qw(SHUT_RD SHUT_WR SHUT_RDWR);
shutdown $sock, SHUT_WR;
Έλεγχος του συγκεκριμένου σφάλματος όταν ένα shutdown αποτυγχάνει σε ήδη κλειστή κατεύθυνση:
unless (shutdown $sock, 1) {
warn "shutdown write failed: $!";
}
Οριακές περιπτώσεις#
Η εγγραφή μετά από
shutdown($sock, 1)αποτυγχάνει και εγείρειSIGPIPE. Η προεπιλεγμένη ενέργεια τερματίζει τη διεργασία· εγκαταστήστε$SIG{PIPE} = 'IGNORE'(ή χειριστή) για να τη μετατρέψετε σε κανονική αποτυχία εγγραφής που μπορείτε να ελέγξετε.Η ανάγνωση μετά από
shutdown($sock, 0)επιστρέφει τέλος αρχείου αμέσως, όχι σφάλμα. Όσα δεδομένα είναι ήδη σε ουρά στον ενταμιευτή λήψης του πυρήνα απορρίπτονται.Δεν είναι υποδοχή: η κλήση
shutdownσε κανονικό filehandle θέτει την$!σεENOTSOCKκαι επιστρέφει0.Μη συνδεδεμένη: η
shutdownσε υποδοχή που δεν συνδέθηκε ποτέ (φρέσκο αποτέλεσμα τηςsocket, ή υποδοχή που ακούει) θέτει την$!σεENOTCONNκαι επιστρέφει0.Διπλό shutdown: ο τερματισμός του ίδιου μισού δύο φορές τυπικά επιστρέφει
0μεENOTCONN. Ο φορητός κώδικας αγνοεί τη δεύτερη αποτυχία αντί να την αντιμετωπίζει ως μοιραία.Κλειστό filehandle: επιστρέφει
undef· υπόuse warningsεκπέμπεται προειδοποίησηshutdown() on closed socket.Ο περιγραφέας δεν κλείνει: η
shutdownαπενεργοποιεί τις κατευθύνσεις που ζητήσατε αλλά αφήνει τον περιγραφέα αρχείου ανοιχτό. Καλέστεclose(ή αφήστε το handle να βγει εκτός εμβέλειας) όταν πραγματικά τελειώσετε με αυτό.Κοινόχρηστοι περιγραφείς μέσω
fork: αυτή είναι η περίπτωση για την οποία σχεδιάστηκε ηshutdown. Όλες οι διεργασίες που κρατούν τον περιγραφέα βλέπουν το shutdown να εφαρμόζεται άμεσα· δεν έχουν ξεχωριστές όψεις.
Διαφορές από το upstream#
Πλήρως συμβατό με το upstream Perl 5.42.
Δείτε επίσης#
close- απελευθερώνει τον περιγραφέα σε αυτή τη διεργασία· δεν επηρεάζει forked αντίγραφα και δεν σηματοδοτεί τέλος αρχείου στον ομότιμο μέχρι να κλείσει το τελευταίο αντίγραφοsocket- δημιουργεί την υποδοχή στην οποία λειτουργεί ηshutdownconnect- εγκαθιδρύει τη σύνδεση· ηshutdownσε μη συνδεδεμένη υποδοχή αποτυγχάνει μεENOTCONNaccept- παράγει τη συνδεδεμένη υποδοχή στην πλευρά του διακομιστή που τυπικά μισοκλείνει μεshutdownSocket- εξάγει τιςSHUT_RD,SHUT_WR,SHUT_RDWRκαι τις υπόλοιπες σταθερές επιπέδου socket$!- συμβολοσειρά σφάλματος συστήματος που ελέγχεται μετά από επιστροφή0