Υποδοχές (sockets)

getsockopt#

Διαβάζει μία επιλογή υποδοχής από τον πυρήνα ως αδιαφανή πακεταρισμένη συμβολοσειρά.

Η getsockopt ζητά από τον πυρήνα την τρέχουσα τιμή της επιλογής με όνομα OPTNAME στο επίπεδο πρωτοκόλλου LEVEL στην SOCKET. Ο πυρήνας δεν επιστρέφει τιμή με τύπο - επιστρέφει έναν ωμό ενταμιευτή bytes του οποίου η διάταξη καθορίζεται από το ζεύγος (LEVEL, OPTNAME). Αποκωδικοποιείτε αυτόν τον ενταμιευτή με unpack, συνήθως με το πρότυπο "i" ή "I", επειδή οι περισσότερες επιλογές είναι απλοί ακέραιοι.

Σύνοψη#

getsockopt SOCKET, LEVEL, OPTNAME

Τι επιστρέφεται#

Μια πακεταρισμένη συμβολοσειρά που περιέχει την απάντηση του πυρήνα σε περίπτωση επιτυχίας, ή undef σε περίπτωση αποτυχίας με το $! ρυθμισμένο στο σφάλμα του συστήματος. Τα περιεχόμενα της συμβολοσειράς είναι αδιαφανή bytes - το μήκος και η διάταξή της εξαρτώνται εξ ολοκλήρου από το (LEVEL, OPTNAME):

  • Οι επιλογές λογικής τιμής και ακεραίου (SO_KEEPALIVE, SO_REUSEADDR, TCP_NODELAY, …) επιστρέφουν ως πακεταρισμένο int. Αποκωδικοποιήστε με unpack χρησιμοποιώντας "i" ή "I".

  • Τα χρονικά όρια (SO_RCVTIMEO, SO_SNDTIMEO) επιστρέφουν ως πακεταρισμένο struct timeval - δύο long στις περισσότερες πλατφόρμες.

  • Οι επιλογές δεσμευμένες σε διεύθυνση (SO_PEERCRED, IP_MULTICAST_IF, structs linger, …) έχουν τις δικές τους διατάξεις· συμβουλευτείτε το getsockopt(2) και τις σχετικές σελίδες man πρωτοκόλλων για το ακριβές struct.

Πάντα ελέγχετε την τιμή επιστροφής πριν την αποκωδικοποίηση - η κλήση unpack σε undef αποδίδει κενό αποτέλεσμα και κρύβει το πραγματικό σφάλμα που καταγράφεται στο $!.

Καθολική κατάσταση που επηρεάζει#

  • Το $! τίθεται σε περίπτωση αποτυχίας στην τιμή errno από την υποκείμενη κλήση getsockopt(2). Δεν εκκαθαρίζεται σε περίπτωση επιτυχίας, οπότε ελέγξτε την τιμή επιστροφής, όχι το $! άμεσα.

Παραδείγματα#

Έλεγχος αν ο αλγόριθμος του Nagle είναι αυτή τη στιγμή απενεργοποιημένος (TCP_NODELAY ενεργό) σε μια υποδοχή TCP:

use Socket qw(IPPROTO_TCP TCP_NODELAY);

my $packed = getsockopt($sock, IPPROTO_TCP, TCP_NODELAY)
    or die "getsockopt TCP_NODELAY: $!";
my $nodelay = unpack("I", $packed);
print "Nagle is ", $nodelay ? "off" : "on", "\n";

Ίδια ιδέα, αλλά με λήψη του αριθμού πρωτοκόλλου TCP κατά τον χρόνο εκτέλεσης από τη βάση πρωτοκόλλων του συστήματος αντί από σταθερά του Socket:

use Socket qw(TCP_NODELAY);

defined(my $tcp = getprotobyname("tcp"))
    or die "no protocol entry for tcp";
my $packed = getsockopt($sock, $tcp, TCP_NODELAY)
    or die "getsockopt: $!";

Ανάγνωση του SO_ERROR για εκκένωση και εκκαθάριση εκκρεμούς ασύγχρονου σφάλματος σε μη μπλοκαριστική υποδοχή μετά από connect ή αφότου η select την επισημάνει ως εγγράψιμη:

use Socket qw(SOL_SOCKET SO_ERROR);

my $packed = getsockopt($sock, SOL_SOCKET, SO_ERROR)
    or die "getsockopt SO_ERROR: $!";
my $err = unpack("i", $packed);
if ($err) {
    $! = $err;
    die "asynchronous socket error: $!";
}

Ανάγνωση του τύπου υποδοχής (SOCK_STREAM, SOCK_DGRAM, …) ενός ήδη ανοιγμένου handle:

use Socket qw(SOL_SOCKET SO_TYPE SOCK_STREAM);

my $packed = getsockopt($sock, SOL_SOCKET, SO_TYPE)
    or die "getsockopt SO_TYPE: $!";
my $type = unpack("i", $packed);
print "stream socket\n" if $type == SOCK_STREAM;

Ανάγνωση επιλογής struct timeval. Το SO_RCVTIMEO επιστρέφει δύο εγγενή long - δευτερόλεπτα και μικροδευτερόλεπτα:

use Socket qw(SOL_SOCKET SO_RCVTIMEO);

my $packed = getsockopt($sock, SOL_SOCKET, SO_RCVTIMEO)
    or die "getsockopt SO_RCVTIMEO: $!";
my ($sec, $usec) = unpack("l!l!", $packed);
printf "receive timeout: %d.%06d s\n", $sec, $usec;

Οριακές περιπτώσεις#

  • Η SOCKET δεν είναι ανοιχτή υποδοχή: η κλήση αποτυγχάνει, επιστρέφει undef, και θέτει το $! σε ENOTSOCK ("Socket operation on non-socket") ή EBADF ("Bad file descriptor") για κλειστό handle.

  • Άγνωστο LEVEL / OPTNAME: ο πυρήνας απορρίπτει το αίτημα με ENOPROTOOPT ("Protocol not available"). Δεν υπάρχει τρόπος να διακρίνετε αυτή την περίπτωση από την περίπτωση επιτυχίας εκτός από τον έλεγχο της τιμής επιστροφής.

  • Ιδίωμα επιστροφής με αλήθεια: το συνηθισμένο getsockopt(...) or die λειτουργεί επειδή μια επιτυχημένη κλήση επιστρέφει μη κενή πακεταρισμένη συμβολοσειρά. Μια απάντηση μηδενικού μήκους θα έκανε το ιδίωμα να αστοχήσει, αλλά καμία επιλογή του πυρήνα δεν επιστρέφει ενταμιευτή μηδενικού μήκους στην πράξη - κάθε ορισμένη επιλογή έχει τουλάχιστον ένα byte payload.

  • Πλάτος αποκωδικοποίησης ακεραίου: χρησιμοποιήστε "i" ή "I" για επιλογές μεγέθους int (SO_KEEPALIVE, TCP_NODELAY, SO_ERROR, …)· χρησιμοποιήστε "l!" ή "L!" μόνο όταν η τεκμηριωμένη διάταξη της επιλογής χρησιμοποιεί όντως εγγενές long. Λάθος πλάτος επιστρέφει σιωπηρά τον λάθος αριθμό σε πλατφόρμες LP64.

  • Μη πακετάρετε την απάντηση χειροκίνητα: η getsockopt επιστρέφει ό,τι έγραψε ο πυρήνας, συμπεριλαμβανομένης κάθε συμπλήρωσης. Επαναπακετάρετε μόνο σε πλήρεις κύκλους μέσω της setsockopt, και τότε περάστε τον ενταμιευτή πίσω αυτούσιο αντί να τον ανασυγκροτείτε.

  • Καμία σταθερά χωρίς Socket: τα SOL_SOCKET, IPPROTO_TCP, TCP_NODELAY, SO_ERROR, και συγγενή δεν είναι ενσωματωμένα ονόματα. Εισάγετέ τα από το Socket με use Socket qw(...) ή use Socket qw(:all).

Διαφορές από το upstream#

Πλήρως συμβατό με το upstream Perl 5.42.

Δείτε επίσης#

  • setsockopt - το μισό εγγραφής· ορίζει την επιλογή της οποίας την τιμή ανακτά η getsockopt

  • Socket - πηγή των σταθερών SOL_*, IPPROTO_*, SO_*, TCP_*, IP_* που περνάτε ως LEVEL και OPTNAME

  • unpack - απαιτείται για την αποκωδικοποίηση της πακεταρισμένης συμβολοσειράς bytes που παραδίδει ο πυρήνας

  • getprotobyname - τρόπος κατά τον χρόνο εκτέλεσης για την απόκτηση του αριθμού πρωτοκόλλου LEVEL όταν δεν θέλετε να εισάγετε τις σταθερές IPPROTO_* από το Socket

  • getsockname - αδελφή κλήση ενδοσκόπησης· επιστρέφει την τοπική διεύθυνση που είναι δεσμευμένη στην SOCKET αντί για μία επιλογή

  • socket - δημιουργεί την υποδοχή την οποία στη συνέχεια ερωτά η getsockopt